I decided to widen my horizon about browsers. After browsing a few subreddits, I have chosen these 3 browsers:
- Arc
- Chromium based
- the team has moved on to Dia, an AI browser
- but people still miss the UX of Arc, it seems to be one of a kind, so I have to know
- unlikely to be open-source
- Mac/iOS/Windows, no Linux
- Orion
- WebKit based, this engine is the best hope for degoogle
- will be open-source
- not mature yetA
- Mac/iOS, Linux WIP, no Windows/Android
- Floorp
- Firefox based
- open-source
- Mac/Windows/Linux, no mobile
Just to note down that it's not straightforward to get perf working.
Here's what worked finally:
First, the container needs to be started with proper capabilities:
```bash
docker run --rm -it --platform linux/amd64 --cap-add PERFMON ubuntu:jammy bash
```
Secondly, some flags need to be set from the VM:
```bash
# this would start a shell in the VM, outside of containers
colima ssh
# don't know why, sudo doesn't work, but it works in a root shell
# -1 or 2 both work
sudo bash -c 'echo -1 > /proc/sys/kernel/perf_event_paranoid'
```
Lastly, install perf in the container:
```bash
apt install -y linux-tools-$(uname -r) linux-cloud-tools-$(uname -r)
```
Then the following works:
```bash
perf record -g echo 1
perf report -g graph,0.5,caller
```
Note also that you can't pass `"echo 1"` because perf will failed to find a file named "echo 1".
Learned this while working on Trying Zig's self-hosted x86 backend on Apple Silicon and before submitting this issue about unable to run `poop` in `colima` containers.
Follow-up:
It's important to check whether certain perf counters actually work:
```
sleep 10 &
perf stat -p $! -e "cpu-cycles,instructions,cache-references,cache-misses,branch-misses"
```
On a machine that supports corresponding counters, it should give something like:
```
Performance counter stats for process id '101011':
511488 cpu-cycles
280194 instructions # 0.55 insn per cycle
16193 cache-references
6161 cache-misses # 38.047 8730 branch-misses
10.009515156 seconds time elapsed
```
On an unsupported machine, the output would be like:
```
Performance counter stats for process id '552':
<not supported> cpu-cycles
<not supported> instructions
<not supported> cache-references
<not supported> cache-misses
<not supported> branch-misses
6.491105847 seconds time elapsed
```
Recently, a MacBookPro and a Mac Mini, both are M4 Pro, have become my primary productivity tools. Along with them, I have 3 monitors, plus the one comes with MacBookPro, counts as 4 screens in total. On top of that, I have the logi MX Keys keyboard and MX Master 3S suite, and an Apple Magic Trackpad.
It turns out that I need to come up with a productive setup for them.
## TL;DR as an ASCII art
```
+---------+
| |
+-----------------+ +-----------------+ | Tall |
| Reference | | Primary | | |
| Display | | Display | | Display |
+-----------------+ +-----------------+ | |
| |
+------+ +------------+ +---------+
| Mini | | MBP |
+------+ +------------+
| [Keyboard] |
| [Pad] |
+------------+
[ MX Keys ] [MX 3S]
[Pad]
```
## Screen arrangement
Above the screen of MacBookPro, I have my primary display, which serves as the main workspace for coding, browsing etc. The second display is placed on its left, on the same height, hosting stuff for reference. Both are horizontal and wide.
The third display (I would like to call it the "tall display") is placed on the right, yet vertically, with its middle part aligned with the primary display, it might host IM, PDFs, AI assistants, or any stuff that are tall, including vertically stacked windows that requires less width.
## Mac-display correspondence
Mac Mini is placed under the second display, and it's connected to the first 2 displays, and all of them if desired.
MacBookPro is connected to the tall display, and optionally also to the primary display.
## Keyboard and mouse
I could just use the keyboard and trackpad of MacBookPro, and they can travel to the nearby Mac Mini.
As I have muscle memory that's already used to MacBookPro's keyboard, MX Keys would be a good fit, as the keys are flatter, the key distance is also shorter.
I'm so used to use the trackpad to scroll, zoom, switching between spaces, and move cursor during coding, so that I would either put MX Keys on top of the keyboard of MacBookPro so I can reach its trackpad effortlessly, or I would just MX Keys and the Magic Trackpad beneath it, with the same relative location like the MacBookPro's keyboard and trackpad.
When I work with diagrams, slides, or UIs that require meticulous mouse control, I would use the MX Master 3S mouse. Its side wheel is configured to send `Ctrl+Left` and `Ctrl+Right`, and side buttons are configured to send `Ctrl+Up` and `Ctrl+Down`, both serving space switching.
The logi keyboard and mouse supports switch between 3 devices, so I can switch between 2 Macs. Unfortunately, one doesn't follow the other to switch, so I would rely on Mac's native support for keyboard and mouse sharing, and it goes like `2->1->MacBookPro->Tall`, so there is minimal extra travel between 1 and tall.
One might noticed that such a setup is highly redundant, but this provides me with maximum flexibility and productivity:
- In coding mode, I could have both hands on the keyboard, with the left hand sometimes on the trackpad
- In browing mode, my left hand is on the trackpad, and the right hand is on the mouse
- In diagramming mode, both hands are also on the keyboard, with the right hand sometimes on the mouse
## Thunderbolt bridge
I also have a Thunderbolt bridge, by connecting 2 Macs with a Thunderbolt cable, and following this guide. This would create a secure and fast connection between them for file transfer, screen sharing, distributed AI inference etc.
Such a bridge could also be used in MX Flow, but it has certain delay each time the cursor moves between the 2 Macs, so I didn't use it.
I wish to note down my exploration of solutions to organize massive amount of (mostly binary media) files.
## Wishlist
- Performant
- it should be able to handle huge amount of files, with cached metadata, thumbnails, etc. so I can browse over their contents quickly
- batch operations to files on NAS should be as performant as local files, e.g. using client-server architecture, using rsync to determine the diff, etc.
- Data integrity
- it should be able to use versioning, deduplication, etc. to ensure data integrity so I can mess with the files (mostly moving around, renaming) without worrying about losing them and their metadata such as timestamp, and this should be efficient in terms of storage
- Semi-auto tagging
- I should be able to tag files manually, in batch, and set rules to tag files automatically with metadata or based on content (using ML models)
- preferably, tags could have its own hierarchy
- tags should not be using filename or metadata, but rather a separate database
- Open-source, freemium or affordable one-time purchase
- in anycase, I should not be locked in, and the data should be exportable, so I can script
## Candidate solutions
- git-annex
- Pros
- it maintains a versioned record for files, can even track offline media
- Cons
- it only have access to the file contents when they are present at the registered location
- even with the web UI, it's not realy user-friendly
- DataLad
- it builds on git-annex, but still a CLI
- kopia
- Pros
- backup, versioning, deduplication, encryption, compression, error correction etc.
- it can mount or restore any snapshot to a directory
- there is official support for syncing the repo, making it reliable to backup the backup
- Cons
- can't really check the history of a file
- relies on other tools for checking file location changes
- lost the time added, preserving only the modification time
- Commander One
- dual-pane file manager, trying out
- `dua -i`
- it can analyze disk usage recursively, interactively
- I can mark files for deletion
- jw
- Pros
- it can calculate the hashes of files in deep directories really quick
- I use it to check the integrity of files after copying files
- Cons
- it doesn't check file renaming/moving
- VeraCrypt
- Pros
- useful if you just want to encrypt files in a container
- Cons
- it's inconvenient to mount in docker
- Garage
- Pros
- it's a S3-compatible storage
- it works with git-annex and kopia
- macFUSE
- needed to mount various filesystems
- photo management
- HomeGallery
- librephotos
- digiKam
- PhotoPrism
- Immich
- Lychee
- asset management
- Eagle 4
- Pixcall
- Billfish
This note will cover some modern C++ features interesting to me during reading Modern C++ Programming.
Features standardized in C++23, or implemented for C++26, are in scope.
This note serves as a holistic view and a reminder.
The problem with using C++...is that there’s already a strong tendency in the language to require you to know everything before you can do anything -- Larry Wall
- C++14 digit separators, e.g. `1'000'000`
- C++14 `auto` for function return types, e.g. `auto f() { return 1; }`
- C++20 `auto` for function input, equivalent to templates but less expensive at compile-time
- C++20 `<utility>` for safely comparing signed/unsigned types
- Detecting wraparound for unsigned integral types is not trivial
- C++23 `std::float128`, `std::binary16`, `std::bfloat16`
- `inf` and `nan` for floating-point types
- Floating-point Arithmetic Properties
- Catastrophic Cancellation
- Fixed epsilon “looks small” but it could be too large when the numbers being compared are very small
- `areFloatNearlyEqual`
- compensation algorithm like Kahan summation, Dekker’s FastTwoSum, Rump’s AccSum
- C++11 Dynamic memory 2D allocation/deallocation: `new int[3][4]` and `delete[]`
- `new (buffer)`: `delele[] buffer`, explicit `x->∼A()`
- `new (std::nothrow)`
- C++20 Designated Initializer List: `struct A { int x, y; }; A a{.x = 1, .y = 2};`
- Pointer arithmetic rule: `address(ptr + i) = address(ptr) + (sizeof(T) * i)`
- C++11 `constexpr`: _can_ be evaluated at compile-time
- variable: always evaluated at compile-time
- function
- evaluated at compile-time as long as all its arguments are evaluated at compile-time
- always evaluated at run-time if
- contain run-time functions
- contain references to run-time global variables
- C++20 `consteval`: guarantees compile-time evaluation
- A run-time value always produces a compile error
- C++20 `constinit`: guarantees initialization at compile-time
- A run-time initialization value always produces a compile error
- The value of a variable _can_ change during the execution
- C++17 `if constexpr`: compile-time branching
- C++20 `std::is_constant_evaluated()`
- C++23 `if consteval`
- C++20 `std::bit_cast`
- `=delete` can be used to prevent calling the wrong overload
- C++20 `[[nodiscard("reason")]]`
- This issues a warning if the return value of a function is discarded (not handled), which is good for ensuring error handling.
- C++17 for the entire class/struct
- C++20 for constructors
- C++23 for lambdas
- The compiler injects `operator()` in the code of the destination function and then compile the routine. Operator inlining is the standard behavior
- C++11 lambda expression: capture clause
- `[]` captures nothing
- `[&]` captures all variables by reference
- `[=]` captures all variables by value
- `[=, x, &y]` captures `x` by value and `y` by reference, all other variables by value
- C++17 `[this]` captures the current object by reference
- C++14 `[x=x]`, `[&x=x]` capture current object member `x` by value/reference
- C++20 deprecates `[=]` capturing `this` pointer by value
- C++14 `[](auto value)`, `[](int i = 6)`
- A function can return a lambda (dynamic dispatch is also possible)
- C++17 `constexpr` lambda, C++20 `consteval` lambda, `mutable`
- syntax: post specifier
- C++20 `template` and `requires` clause for lambda
auto lambda = []<typename T>(T value)
requires std::is_arithmetic_v<T> {
return value * 2;
};
auto v = lambda(3.4); // v: 6.8 (double)
struct A{} a;
// auto v = lambda(a); // compiler error
- When Preprocessors are Necessary
- Conditional compiling
- [Abseil Platform Check Macros](https://abseil.io/docs/cpp/platforms/macros)
- Mixing different languages
- Complex name replacing
- [Are We Macro free Yet, CppCon2019](https://github.com/CppCon/CppCon2019/blob/master/Presentations/are_we_macrofree_yet/are_we_macrofree_yet__zhihao_yuan__cppcon_2019.pdf)
- C++20 `<source location>`
- replaces `__FILE__`, `__LINE__`, C++11 `__func__`
- still: non-standard `__PRETTY_FUNCTION__`
- C++17 [`__has_include`](https://en.cppreference.com/w/cpp/preprocessor/include)
- stringizing macro operator `#`, e.g. `#string` expands to `"string"`
- token pasting macro operator `##`, e.g. `x##y` expands to `xy`
- `#error`, C++23 `#warning`
- non-portable `pragma`, C++11 `_Pragma`
- C++11 `__VA_ARGS__`
- C++11 In-class non-static data members initialization (NSDMI)
- allows initializing the data members where they are declared
- a user-defined constructor can be used to override their default values
- C++11 uniform initialization `{}`
- in function arguments and return values
- C++11 delegate constructor
- C++11 `=default`, `=delete`
- `using` for type aliasing
- e.g. partial specialization for templates
- C++11 `override`
- ensures that the function is virtual and is overriding a virtual function from a base class
- C++11 `final`
- prevents a virtual function from being overridden in a derived class
- `dynamic_cast`
- upcast: `dynamic_cast<Base*>(derived)`
- C++23 multidimensional subscript operator `[]`
- C++23 static `[]` and `()` operators
- C++11 `explicit` for conversion operators
- `std:swap`
- operators preserve precedence and short-circuit properties
- binary operators should be implemented as friend methods
- layouts
- aggregate
- initializable with `{}`
- trivial copyable
- can be copied with `memcpy`
- standard layout
- just like a struct or a union
- POD
- trivial copyable + standard layout
- C++11/C++20 `<type_traits>` to check layout
- C++17 automatic deduction of non-type template parameters, with `auto`
- non-type template parameters
- C++20 a class literal type
- `constexpr` assignable
- public, non-mutable
- for all base classes and non-static data members
- pointer, reference, and pointer to member
- function, e.g. `decltype(f)`
- C++26 assertion with text formatting
- e.g. `static_assert(sizeof(T) != 4, std::format("test1 with sizeof(T)={}", sizeof(T)));`
- `decltype((expr))` for `lvalue` reference to the type of `expr`
- C++14 `auto` for function template return types
- replaces e.g. `decltype(T{} + R{})`
- `<type_traits>`
- type query
- type manipulation
- C++17 CTAD
- automatic deduction of class template arguments in constructor calls (CTAD)
- template deduction guide
- map constructor parameter types to class template parameters
- e.g. `MyString(char const*) -> MyString<std::string>;`
- doesn’t work within the class scope
- C++20 alias template deduction
- use `std::enable_if` to make use of SFINAE
- helper alias: `_t` for `::type`, `_v` for `::value`
- using `std::enable_if_t` for the return type prevents `auto` deduction
- variadic template
- captures a parameter pack of arguments, which hold an arbitrary number of values or types
- ellipsis `...`
- prefix an identifier to introduce/capture
- suffix the identifier to expand
- `sizeof...(args)` to get the number of arguments
- C++17 fold
`(other op ... op pack)`
- C++14 for lambdas
- C++20 for concepts
- [C++20 idioms for parameter packs](https://www.scs.stanford.edu/~dm/blog/param-pack.html)
- C++20 concepts
- `concept [name] = [compile-time boolean expression];`
- `requires` clause: `requires [compile-time boolean expression or Concept]`
- `requires` expression:
#include <concept>
requires [(arguments)] {
[SFINAE contrain]; // or
requires [predicate];
} -> bool
template<typename T>
concept MyConcept = requires (T a, T b) { // First case: SFINAE constrains
a + b; // Req. 1 - support add operator
a[0]; // Req. 2 - support subscript operator
a.x; // Req. 3 - has "x" data member
a.f(); // Req. 4 - has "f" function member
typename T::type; // Req. 5 - has "type" field
{*a + 1} -> std::convertible_to<float>;// Req. 6 - can be deferred
// and the sum
// with an integer is convertible
// to float
{a * a} -> std::same_as<int>; // Req. 7 - "a * a" must be valid
// and the result type is "int"
};
- common linker errors
- multiple definitions
- undefined reference
- C++20 modules
- a module is a set of source code files that are compiled independently of the translation units that import them
- `module module.name;`
- `import module.name;`
- `export`
- `export { ... }`
- `export module module.name;`
- `expor import module.name;`
- global module fragment: include header files in a module interface
- `module;`
- private module fragment: include header files in a module implementation
- `module :private;`
- legacy headers can be directly imported with import
- all declarations are implicitly exported and attached to the global module (fragment)
- a module can be organized in isolated module partitions
- namespace
- anonymous namespace
- visible only in the translation unit, internal linkage
- inline namespace
- can be used to version a library
- C++17 attributes on namespaces
- tools
- `c++filt`, `ldd`, `nm`, `objdump`, `readelf`
- “Common” Project Organization
- [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines)
- Naming style conventions can be also enforced by using tools like `clang-tidy`'s [readability-identifier-naming](https://clang.llvm.org/extra/clang-tidy/checks/readability/identifier-naming.html#readability-identifier-naming)
- Use braced direct-list-initialization or copy-initialization for setting default data member value. Avoid initialization in constructors if possible
struct A {
int x = 3; // copy-initialization
int x { 3 }; // direct-list-initialization (best option)
};
- C++20 Ranges
- operate on elements of data structures uniformly
- pipe operator `|`, `|=`
- `std::views::*`, `std::actions::*`
- range factory: produces a view that contains no elements
- lvalue, rvalue (could be *p*ure rvalue, or e*x*piring *g*eneralized lvalue)
- `std::move` indicates that an object is no longer needed and can be moved
- C++11 reference collapsing rules
- C++11 perfect forwarding with `std::forward`: allows preserving argument value category and const/volatile modifiers
- copy elision for return value (C++17 guarantees some cases)
- C++23 decay copy with `auto`
- C++23 `std::expected`
- return a value or an `std::unexpected`
- the user can choose how to handle the error: check return value, throw an exception, or monadic operations
- future
- `std::async(f, args)`
- launch policy: `std::launch::async`, `std::launch::deferred`
- `.get()` or `.wait()`
Setup:
- Use SketchyBar
- Use `just prep-sbar` to setup SketchyBar
- Use `just prep-skhd` to setup some extra key bindings
- `Shift + Alt + space`: toggle sketchbar
- Modify `~/.config/sketchybar/bar.lua` as follows:
```lua
display = "all",
sticky = true,
```
for better multi-monitor support, and make the bar sticky.
Unfortunatly, SketchyBar actively hides itself for fullscreen spaces, see this issue for more info.
So, remember to use `Cmd + Ctrl + F` to toggle fullscreen mode.
Setup:
- Use Amethyst
- sensible default
- less confusing configuration than yabai it seems
- Use `just prep-tile` to install Amethyst
Keys:
- `Option + Shift + Space` to cycle through layouts
- I prefer only BSP and wide
- `Option + Shift + J/K` to cycle through windows
- `Option + Shift + H/L` to resize windows
Alternative setup:
- Use yabai
- requires skhd for key bindings
- Use `just prep-yabai` to install yabai
- Intentionally choose not to disable SIP
Keys:
- Space manipulation won't work with SIP enabled
- keys to switch between windows are confusing
- place windows on another window to split with it, there is visual hint for the split layout when overlapping with different areas
- `Shift + Alt + s`: change how windows are splitted, prefer use Kitty's own layout management
- `Ctrl + Alt + g`: toggle gaps between windows, prefer some gap for normal apps but no gap for terminals
Setup:
- Use Kitty
- Use `just prep-kitty` to install Kitty
Keys:
- Font size
- `Cmd +` to increase font size
- `Cmd -` to decrease font size
- OS Windows
- `Cmd + N` to open a new OS window with the same current directory
- Tabs
- `Cmd + T` to open a new tab with the same current directory
- `Cmd + number` to switch to tab number
- particularly useful for tiled windows, as SketchyBar will hide the tab bar
- `Cmd + w` to close the current tab
- Kitty Windows
- `Cmd + Enter` to open a new window with the same current directory
- close the current Kitty window
- `Ctrl + Shift + w`
- or run `exit`
- `Ctrl + Shift + l` to switch to next layout
- `Cmd + r` to resize window, e.g. `t` to make it taller
- Kitty
- `Cmd + q` to quit kitty
- `Cmd + ,` to open kitty config file
- with `Ctrl` to reload config
Here are some useful keys that I like using in NeoVim, some of them require corresponding plugins.
I use
- LunarVim
- it has some pre-installed plugins
- Task `prep-lvim` in my justfile is how I have installed LunarVim. Task `lvim` will syncrhonize the configurations, change the working directory and open LunarVim for a specified project.
- my LunarVim configuration
- LunarVim specific keys are marked with 🌕
- AstroVim
- seems to be a better starting point
- see astrocommunity for configuring plugin packs
- I've ported plugins to use it except for forester
- AstroVim specific keys are marked with 🌌
- LazyVim
- it has some pre-installed plugins
- similarly, see task `prep-lazyvim` and `lazyvim` in my justfile
- LazyVim specific keys are marked with 💤
- NvChad
- it's ~ 900 LOC lightweight configuration
- see tasks `prep-chad` and `chad` in my justfile
- NvChad specific keys are marked with 📦
- For all Vim flavors, the following apply:
- shared configurations
- shared plugins
The `Esc` key is used to escape to normal mode, to use Vim's powerful motions. It's the most frequently used key in Vim.
- I have configured CapsLock to mean Esc
- on Mac, go to `System Preferences > Keyboard > Modifier Keys > Caps Lock Key`
- I have configured `jk` in insert mode to mean Esc
- this is a common practice, but I don't seem to need it much
The leader key is used to trigger many key mappings in normal mode.
The default leader key is a single space, represented by `<leader>` below.
🌕 The default local leader key is not set. I've configure it to be two consecutive spaces. `,` is also a common choice.
💤 The default local leader key is set to `\\`. I didn't change it.
With plugin `whichkey` installed, `<leader>` and wait to see some useful mappings.
Most frequently used key mappings is `<leader>` + one character. There are also many two-character mappings, with the first character indicating a category.
> To generate a truly random string, place a new user in front of Vim and ask them to exit
Most of the time, one can use `Esc` + `:qa!` to force quit Vim, with potential loss of unsaved changes.
In most plugin UIs,
- it can be quit with a single `q`, or `Esc` + `:q`, when in despair, try also `Ctrl+c`
- it will usually enter normal mode first, even in terminals, a single `i` is required to enter insert mode, to acually type something
- it might provide visual hints on how to navigate, usually a single number or a character in brackets
- `g?` or `?` might bring up help on key mappings.
Recording is a powerful feature of Vim, but one can accidentally trigger it with an out-of-order `q`, so one simply need to remember to press `q` again to quit recording if seeing something like `recording @a` in the status bar.
Other first aid key mappings or commands available:
- `:map` to see all key mappings
- `:help key-notation`
- in case it's not immediately clear that
- `C` means `Ctrl`, `S` means `Shift`
- `M` means `Alt`/`Option`
- `D` means `Cmd` on Mac
- use `:Lazy` to check on plugins
- use `:Mason` to check on LSPs
- 🌕
- `<leader>+;` to open the dashboard for frequently used actions
- `<leader>+Lr` to reload the config
- `<leader>+li` to see LSP informations
- 📦
- `<leader>+ch` to open cheatsheet
- Theming
- dropping into an unfamiliar theme is worth a first aid
- `:colorscheme ` and tab to select a theme
- 🌕 `<leader>+sp` to search/select and preview themes
- my favorite is `railscasts`
- 💤 defaults to `tokyonight`
- 📦 defaults to `onedark`
- Resume session
- `<leader>+rs` to resume the last session
- `<leader>+rS` to select a session to resume
- Explore and find files
- `<leader>+e` to toggle file explorer on the left
- `x` to cut, `c` to copy, `p` to paste
- `a` to create a file, `d` to delete, `r` to rename
- `H` to toggle hidden files, `I` to toggle git ignored files
- `Y` to copy relative path, `gy` to copy absolute path
- `s` to open in system file explorer
- `g?` for help, `q` to quit, `R` to refresh
- `hjkl` to move up/down, collapse/expand
- it will automatically follow the current file
- 💤 and 📦 use NeoTree
- can't be toggled, need `q` to quit
- `?` for help
- 🌕
- `<leader>+sr` to fuzzy find recent files
- `<leader>+sf` to fuzzy find files
- `<leader>+st` to grep text in files
- `<leader>+bf` to fuzzy find buffers
- 💤
- `<leader>+fr` to fuzzy find recent files
- `<leader>+ff` to fuzzy find files, or simply double space
- `<leader>+/` to grep text in files
- Manipulate buffers and windows
- use `L` for going to next buffer, `H` for previous buffer
- use `<C-hjkl>` to move between windows
- use `-`/`=` to resizing, or with `C-` for vertical resizing
- Jump between files
- `gd`: go to definition
- `Ctrl`+click also works, note that it's not cmd+click on mac
- `gl`: show diagnostics under cursor
- `<C+o>`: go back, `<C+i>`: go forward
`:jum` to see the jump history
- `gf`: go to file
- `K` : hover, backspace to cancel hover
- `Shift`+click on URL to open in browser
- In-file outline
- `<leader>+o` to toggle the outline on the right
- I have configure it to autojump and autoexpand
- Folding
- the following needs to be run inside the fold
- otherwist it will work on the upper level
- `za` to toggle fold
- `zA` to toggle all folds
- `zO` or `zC` to open/close folds recursively
- e.g. it's useful `zCV` then `<leader>+/` to toggle comment for a fold range
- Open file
- `:e` to open a file, with tab completion, but it's better to use the fuzzy finder above
- `:vs` to open a file (or the current buffer) on the right
- `:sp` to open a file (or the current buffer) on the bottom
- Save & quit
- `:bd` (i.e. buffer delete) to close the current buffer/tab
- won't close if there are unsaved changes, `:bd!` to force close
- In VSCode Vim mode, should stick to `cmd+s` for saving, `cmd+w` for closing a tab
- 💤
- `:w` or `Ctrl+s` to save
- `<leader>+bd` to close a buffer with confirmation on unsaved changes
- 🌕 prefer to use
- `<leader>+w` to save
- `<leader>+c` to close a buffer with confirmation on unsaved changes
- `ZZ` to save and quit
- Repeatition
- prefix with a number to repeat a motion multiple times, e.g. `3j`, `3w` for the impatient
- `.` to repeat the last edit motion, but not move motions
- Move motions
- On Mac, combine with the touchpad to be even more efficient
- `gg` for beginning, `G` for end
- `zz` to center the current line, `zt` to top, `zb` to bottom
- prefixing with a number works on the corresponding line
- `w`/`b` to move forward/backward by word
- `W`/`B` to move by space-separated words
- `e` works like `w` but moves to the end of the word
- `ge` works like `b` but moves to the end of the previous word
- left `hj` are for left, down; right `kl` are for right, up
- pointer finger on `j`, then muscle memory for `jkl` but `h` is a little difficult to reach
- `0` to move to the beginning of the line
- I don't like `^` and `$` because they are difficult to reach
- but in the case of `d$`, it's worth it to reach for `$`
- `f` + character to move to the next such character on the same line
- `;` and `,` to move to next or previous
- `t` works like `f` but moves to one character before, just like `i` for `a`
- e.g.
- `ct)` is useful for change until the next `)`
- `vt)p` is useful for select until the next `)` and paste and replace
- `F` and `T` work like `f` and `t` but move backward
- `}` to the next paragraph
- Edit motions
- to enter INSERT mode
- `i` for before the cursor
- `I` to insert at non-whitespace beginning of the line
- `0i` to insert at the beginning of the line
- `a` for after the cursor
- `A` to append at the end of the line
- `c` (i.e. change) to replace by motion, e.g. `cw` to replace a word
- `R` to replace by character
- `u` to undo, surprisingly `Ctrl+r` to redo
- Text objects
- `i` for inside, `a` for around
- works after the action, before the motion
- e.g. `ciw` to *c*hange *i*nside the *w*ord
- note that `cw` only changes the part of the word after the cursor, but `ciw` changes the whole word
- `a` will affect the surrounding whitespace and punctuation
- with `mini.ai` extending the text objects, we have more general way to discribe the text objects
- `b` for brackets
- `q` for quotes
- `c` for class
- `f` for function bodies
- `a` for arguments
- `?` to specify left and right delimiters interactively
- Cut/copy/paste
- `x` to immediately delete the character under the cursor
- `d`+direction to delete a character in that direction
- prefer to use number + `dj`/`dk` to delete multiple lines
- `dw`/`dd` to delete a character/word/line
- all the above will also cut the deleted text
- `yw` to copy the current word, `yy` to copy the current line
- `p` to paste after, `P` to paste before
- for pasting into a pair of brackets/quotes etc., move to the opening one (e.g. use `Esc` + `b`), then `p` or `Cmd+v`
- `yyp` to duplicate a line
- `<leader>+s+R` to search the registers for cut/copied text
- on Mac, `Cmd`+`c`/`v`/`x` also works despite which mode Vim is in
- but it seems to be not working stably across difference instances of Vim, especially when inside various plugins
- `y` usually guarantees the text is copied to the system clipboard, then use it in other applications
- Search
- `/` to search forward, `n`/`p` to go to next/previous match
- `?` to search backward
- `*` to search the word under the cursor
- remember to press `Enter` after typing the search term
- remember to treat the search as a regex
- i.e. to escape `\`, `()`, `[]`, `{}`, `^`, `$`, `*`, `+`, `?`, `|`, `.` etc.
- use `<leader>+h` to clear the search highlight
- `gn` to select the next match, `gN` to select the previous match
- repeating this would select *to* the following matches
- prefix with an operator to operate on the selected text
- Replace
- use `%s/before/after/g` to replace all occurrences, remember`%`, otherwise it will only look for the pattern in the current line
- `<leader>+ss` to toggle the search and replace panel
- `<localleader>+r` to replace all occurrences
- manually: use `gf` to go to each file, do edits, then `Ctrl+o` to go back and continue for the next file
- Select text
- use `V` to enter line visual mode
- this is the most frequently used visual mode, to select multiple lines
- lowercase `v` can be used for character visual mode, but I find it less useful
- `Ctrl+v` to enter block visual mode, i.e. select by column
- Indentation & comment
- use `<<`/`>>` to indent/unindent the current line
- use a single `<`/`>` to unindent/indent the selected text
- 🌕
- `<leader>+/` to toggle comment
- works for both current line and selected text
- 💤
- `gc` to toggle comment for selected text
- `gcc` to comment/uncomment a line
- Multiple-cursor editing (⧉)
- use `/xyz` + enter to search for `xyz`, then `cgn` to change it to something else, `Esc`, then
- use `.` to do the same for next occurrences
- use `n` to skip, and `u` to undo
- use `Ctrl+v` and direction keys (e.g. `j` or `5j`) to vertically select
- use `c` to change
- use `I` to prepend
- use `A` to append
- use `d` to delete
- type the new text, then `Esc`, then it will be applied to all lines of selection
- use `gv` to reselect the last selection
- Visual selection with mouse/touchpad
- motion-compatible selections
- dragging works like `v`
- triple click + scroll works like `V`
- `alt/option` + drag works like `Ctrl+v`
- select and
- ✅ delete by `d`/`x`
- ✅ cut/copy/paste
- ✅ comment/uncomment
- ❌ typing
- ✅ use one of `i`, `a`, `c` etc., then start typing
- ❌ indent/unindent with `Tab`/`Shift+Tab`
- ✅ indent/unindent with `<`/`>`
- vertical select and
- ✅ delete
- ✅ paste
- ❌ typing
- ✅ use one of `I`, `A`, `c`, then start typing
- Recording
- `qa` starts recording user's inputs, `q` quits recording, `@a` replays the recording, `a` could be any other letter
- it could serve as ad hoc key mappings
- Diagnostics
- by default, diagnostics are shown as virtual text, I've disabled it for now
- `<leader>+l` with `j`/`k` to move between diagnostics
- `<leader>+ld` to show diagnostics in the current buffer
- `<leader>lw` can search for diagnostics in workspace
- `Trouble` can be used to show diagnostics in a separate panel
- `<leader>+xx` to open the trouble panel at the bottom
- use `<leader>+xX` to see only the current buffer's diagnostics
- click on diagnostics to jump to the corresponding location
- `<leader>+lq` to open the quickfix list
- `<leader>+la` to open the code action list
It's very important to stay in the flow and Zen mode as much as possible. Split windows for terminals breaks the flow, so I prefer to use float terminals.
- Float terminals
- 🌕 `Ctrl+\`to toggle a float terminal
- 🌕 number + `Ctrl`+backslash to toggle the n-th float terminal
- 💤 same, but with `Ctrl+/`
- it's insert mode on first launch
- but usually enter normal mode when lost focus
- Split terminals
- `:term` to open a terminal
- it's normal mode by default, `i` to start typing commands
- `:sp term://zsh` to open a terminal running `zsh` at the bottom
- 📦
- use `<leader>+h` to open a new horizontal split terminal
- `:q` to hide terminal
- `<leader>+pt` to pick hidden terminal
- Working inside the terminal
- `exit` will exit the terminal and close the window associated with it
- `Ctrl`+`c` can be used for interrupting the terminal
- git
- install and use `lazygit`
- `<leader>+gg` to open lazygit, `q` to quit
- on a file/directory
- space to stage/unstage, `i` to ignore, `d` to discard
- `c` to commit, `P` to push, `p` to pull
- `r` on a commit to reword
- in editor, `<leader>+gs` to stage the current hunk, `<leader>+gr` to revert the current hunk
- usually lazygit is good enough, one can also use `:DiffviewOpen` to inspect diff and handle merge conflicts
- Github Actions
- `<leader>+ga` to open the Github Actions split window
- deprecated: `<leader>+gh` because it conflicts with 💤
- `gj` to open the job under cursor, `gr` for the run, `gw` for the workflow file
- `<leader>+gq` to close the split window
- Octo
- `:Octo <Tab>` to operate on issues and PRs
- it's interesting but I've disabled it for now, in favor of using the web interface
- Auto-complete
- with Github Copilot
- `:Copilot setup` to authenticate etc.
- `Tab` to accept suggestions
- `Shift+Tab` to use the normal Tab
- with `blink.cmp`
- I've configure it to not triggered by default, in favor of Github Copilot
- toggle by `Ctrl+q`
- could also be triggerd by `down` in insert mode
- up/down to cycle through suggestions, `Enter` to accept
- the above is set up so all this key mapping are explicit, intuitive and won't interfere with `<Tab>` for Github Copilot
- with `nvim-cmp` (deprecated)
- `Tab` to cycle through suggestions from `cmp`, reverse cycle with `Shift+Tab`
- continue to type to select a suggestion, this is better then hitting `Enter`
- `Ctrl+e` to reject suggestions, and `Tab` to take suggestions from Github Copilot
- LLM Chats
- Github Copilot
- `<leader>+aa` to toggle the chat, `<leader>+al` to clear chat history
- `<leader>+a` + a character
- for selected code block, **e**xplain, **r**eview, **o**ptimize, **R**efactor, **t**est
- **d**ebug, **f**ix, co**m**mit log, **n**aming etc.
- `?` to select the model
- `C-s` to send the prompt
- `:help copilot` to learn more
- Aichat
- `aichat` with a little setup at `~/Application Support/aichat/config.yaml`
- `.` + tab to see available commands
- Aider
- it's great for multiple-file code generation
- I've created a `aider` shim to run it in a virtual environment with preferred configurations
- `/` + tab to see available commands
- mostly it's a combination of `/add`, `/web`
- use `/token` to check token usage, use `/clear`, `/drop` and check `/map` to save token usage
- Code Companion
- `<localleader>+a` to toggle the inline chat (works also for selection)
- `<localleader>+z` to toggle the chat sidebar
- Parrot
- `<leader>+pr` to rewrite the selection
- `<leader>+pp` to implement the selection
- `<leader>+pn` to start a new chat, optionally with the selection
- select and `:Prt` + `<Tab>` to select advanced prompts
- `:PrtInfo` to inspect configurations
- `:PrtModel` to select the model
- I've configured it to use a buffer to input the prompt, escape twice to send it
- it seems unable to stop generation sometimes, use `:PrtChatStop` to stop
- Avante (deprecated for now)
- `<leader>+aa` to open the chat, use `a` to accept individual suggestions, or `A` to accept all
- select code and `<leader>+ae` to modify code
- it's interesting but I've disabled it for now, in favor of Github Copilot
- Spellcheck
- to use NeoVim's built-in spellcheck
- use `:set spell`
- `]s`/`[s` to move between misspelled words
- `zg` marks a word as good, `zw` marks a word as wrong
- `zug`/`zuw` to undo
- `z=` to see suggestions
- Conform
- formart on save using LSP default formatter
- `<leader>+lf` to format the current file
- showkeys
- `<leader>+kk` to show keys screencaster on top-right corner
- symbols
- `<leader>+se` to fuzzy search symbols, e.g. emoji, LaTeX
- Lean
- set local leader to " " (tentative)
- `<localleader>+i` to toggle Lean Infoview
- `<localleader>+r` to restart Lean server for the current file
- Forester
- `<localleader>+c` to create a new tree and open it
- `<localleader>+b` to browse and search trees by title
- `gf` to go to the tree under the cursor
I wish to be able to call rust libraries that are WASM compatible to use it for both BSR and SSR.
Here is my initial survey:
- wasm-pack and wasm-bindgen are the two main tools for building and binding rust to javascript, more info see awesome-rust-and-webassembly
- I wish to write one-file Rust and specify the dependencies in the file, rust-script is similar in spirit but it's for server-side execution.
- I wish to find prior art on doing this with bun, found bun-ffi-rust and hyperimport, but again, it's for server-side execution.
One could use GlslEditor (which provides widgets to adjust colors, 1-3D numeric values etc.), GlslCanvas or glslViewer to play with the shaders. They are crreated by the authors of The Book of Shaders.
stackgl provides many packages for using in GLSL. LYGIA is a similar effort, targeting a wider range of languages: GLSL/HLSL/MSL/WGSL/CUDA, it also has great integration with many tools, including ObservableJS.