Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

bits 1

I began to explore the terrain for a Word plugin for the company I’m working at.

  • Although there is a common format for the manifest file, Outlook and Word add-ins seem to require separate files. I haven’t seen any add-in in AppSource that serves as both a Word and an Excel add-in.

  • Microsoft provides a tool called Script Lab that allows you to run arbitrary scripts and test APIs directly within Office.

  • For authentication, it is recommended to open a browser window to your web app using the Dialog API.

  • It is usually not possible to use iframes to obtain authentication tokens from the task pane or sidebar itself. See this answer for more details.

  • It is possible to add elements to the right-click menu in Word for add-in commands.

bits 2

We are using a vector database for semantic search. Currently, we employ Pinecone for vector search.

I noticed there is an open-source vector database called Qdrant (pronounced quadrant) that can replace it.

There are other options like pgvector for PostgreSQL.

bits 3

I noticed a channel library that predates crossbeam in Rust. It’s called comm, and the code was last updated eight years ago.

bits 4

I want to use channels for Xvc pipelines. A thread will be created for each step and will receive dependency state changes via channels.

Note that there may be thousands of dependencies (e.g., files for a step), and creating these channels beforehand is not feasible.

The Crossbeam library has Select which allows waiting for an arbitrary number of channels. Now, I need to figure out how to structure the threads and update their states. A minor task! 😆

bits 5

I found a little tool where you describe a diagram in plain text, and it draws it. It likely uses a ChatGPT-to-Mermaid converter.

bits 6

We’re using Graphite at work. Today, I configured a tmux shortcut to open a new pane and run gt create, which creates a new branch and commits all staged Git files.

bind-key -n S-F12 split-window -h -c "#{pane_current_path}" "gt c"

I just hit Shift-F12, and it opens a new pane in the current directory and runs the command.

bits 7

I noticed it’s not possible to unmap the F1 key in Neovim using vim.api.nvim_del_keymap if it’s not already registered. Instead, you can simply override it with something like:

vim.keymap.set({ "n" }, "<F1>", ":Telescope buffers<CR>", { noremap = true, desc = "Find buffer" })

Bits 8

Using ENV.fetch("MY_ENV_VAR", default_value) is preferred over ENV["MY_ENV_VAR"] for specifying default values. While it is similar to ENV["MY_ENV_VAR"] || default_value, fetch is more explicit and idiomatic in Ruby.

Bits 9

I have quite a few LazyVim plugins, but this simple keymapping makes my life much easier:

vim.keymap.set({ "n", "i" }, "<F2>", '<esc><esc>yy:r!<c-r>"')

I type a command, like ls, on a line and hit <F2>. That line is copied, executed, and the output is read into the buffer just below it.

I use it for all sorts of tasks, from listing open PRs with gh to fetching website text with w3m. It has significantly improved my workflow, allowing me to use the shell effectively within textual notebooks.

bits 10

I believe in the value of reducing friction when taking notes. Today, I added a function to my Neovim configuration to create a timestamped file and open it for editing.

function CreateTimestampedFile()
  local zkdir = os.getenv("HOME") .. "/github.com/iesahin/garden/zk/"
  local timestamp = os.date("%Y%m%d%H%M%S")
  local filename = zkdir .. "/" .. timestamp .. ".md"
  vim.cmd("edit " .. filename)
end

vim.api.nvim_set_keymap("n", "<leader>F", ":lua CreateTimestampedFile()<CR>", { noremap = true, silent = true })

Now, I can just hit <leader>F (which is <Space>F in my setup) and immediately start adding a note to my zettelkasten.

bits 11

  • Awk is executed using awk 'awk_program' data-file.
  • Awk programs follow the form pattern { action }; pattern { action };.
  • BEGIN blocks are executed before reading the data files.
  • END blocks are executed after reading the data files.
  • NR is a variable that indicates the number of records (rows) read so far.
  • -F '<separator>' is used to define a field separator for a file.
  • A space is the default field separator.
  • FPAT is a regex used to define the pattern for each field.
  • FPAT is specifically defined in Gawk.

bits 12

I decided I needed a random colorscheme selector for those moments when you want to change things up but don’t want to make a specific choice. LazyVim already has <leader>uC for selecting a colorscheme, but it can be too mentally taxing as it requires you to manually select one. This script simply switches to a random one.

RandomColorScheme returns the name of a random colorscheme after searching through all available paths. SetRandomColorScheme sets the colorscheme to that choice. The keybinding is mapped to <leader>uR.

function RandomColorScheme()
  local color_schemes = vim.fn.globpath(vim.o.rtp, "colors/*.vim", false, true)
  for i, fullpath in ipairs(color_schemes) do
    color_schemes[i] = fullpath:match(".*/(.*).vim$")
  end

  -- Generate a random index
  local index = math.random(#color_schemes)

  local random_color_scheme = color_schemes[index]

  vim.notify("Random Color Scheme: " .. random_color_scheme)
  -- Select a random color scheme
  return random_color_scheme
end

function SetRandomColorScheme()
  vim.cmd("colorscheme " .. RandomColorScheme())
end

vim.api.nvim_set_keymap("n", "<leader>uR", ":lua SetRandomColorScheme()<CR>", { noremap = true, silent = true })

bits 13

I needed a Markdown server to preview my Zettelkasten notes on mobile. I tried installing Lanyon, but its installation instructions are outdated, and the project hasn’t been updated in seven years.

I also looked at rustmark, but configuring it simply to list Markdown files felt like too much effort.

Ultimately, I decided to use dufs and view the files as plain text. It supports basic file operations and WebDAV, which is more than sufficient for my needs.

bits 14

There are three key points highlighted in How to Build Good Software:

  • Reusing good software is easy; it is what allows you to build good things quickly;
  • Software is limited not by the amount of resources put into building it, but by how complex it can get before it breaks down; and
  • The main value in software is not the code produced, but the knowledge accumulated by the people who produced it.

These points lead me to view software development as more of a social profession than a purely technical one. Good software is a reflection of healthy interactions within an organization. When communication is difficult, it becomes much harder to accumulate knowledge about organizational needs, manage complexity, and effectively reuse software components.

bits 15

How to use a Python virtual environment with Nushell:

virtualenv .venv
overlay use .venv/bin/activate.nu

bits 16

I wanted to get the number of word changes between commits in my blogs. I asked for a git diff based nushell pipeline from Gemini:

Gemini proposed this:

git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -r '\{\+|\+\}' '' | str join " " | str words | length

What I ended up doing:

git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -a "{+" "" | str replace -a "+}" "" | str replace -a ' ' "\n" | lines | length

I notice LLMs tend to err on the side of complexity. I don’t know if this is due to their training to spit as many tokens as possible, but using regular expressions when a simple single replace may suffice is a good sign that they may be adding more complexity than necessary.

bits 17

I wanted to calculate the number of words added between commits in my blog posts. I asked Gemini for a Nushell pipeline based on git diff:

It proposed the following:

git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -r '\{\+|\+\}' '' | str join " " | str words | length

However, I ended up using this simplified version:

git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -a "{+" "" | str replace -a "+}" "" | str replace -a ' ' "\n" | lines | length

I’ve noticed that LLMs often lean toward overly complex solutions. I’m not sure if this is due to being trained to generate as many tokens as possible, but using regular expressions where a simple string replacement would suffice is often a sign of unnecessary complexity.

bits 18

I wanted to get the number of word changes between commits in my blog. I asked for a git-diff-based Nushell pipeline from Gemini.

Gemini proposed this:

git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -r '\{\+|\+\}' '' | str join " " | str words | length

What I ended up doing:

git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -a "{+" "" | str replace -a "+}" "" | str replace -a ' ' "\n" | lines | length

I notice LLMs tend to err on the side of complexity. I don’t know if this is due to their training to spit out as many tokens as possible, but using regular expressions when a simple string replacement may suffice is a good sign that they may be adding more complexity than necessary.

bits 19

I wanted to get the number of word changes between commits in my blog. I asked for a git-diff-based Nushell pipeline from Gemini.

Gemini proposed this:

git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -r '\{\+|\+\}' '' | str join " " | str words | length

What I ended up doing:

git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -a "{+" "" | str replace -a "+}" "" | str replace -a ' ' "\n" | lines | length

I notice LLMs tend to err on the side of complexity. I don’t know if this is due to their training to spit out as many tokens as possible, but using regular expressions when a simple string replacement may suffice is a good sign that they may be adding more complexity than necessary.

bits 20

I wanted to get the number of word changes between commits in my blog. I asked for a git-diff-based Nushell pipeline from Gemini.

Gemini proposed this:

git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -r '\{\+|\+\}' '' | str join " " | str words | length

What I ended up doing:

git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -a "{+" "" | str replace -a "+}" "" | str replace -a ' ' "\n" | lines | length

I notice LLMs tend to err on the side of complexity. I don’t know if this is due to their training to spit out as many tokens as possible, but using regular expressions when a simple string replacement may suffice is a good sign that they may be adding more complexity than necessary.

bits 21

I wanted to get the number of word changes between commits in my blog. I asked for a git-diff-based Nushell pipeline from Gemini.

Gemini proposed this:

git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -r '\{\+|\+\}' '' | str join " " | str words | length

What I ended up doing:

git diff --word-diff=plain -- "*.md" | rg -o '\{\+(.*?)\+\}' | str replace -a "{+" "" | str replace -a "+}" "" | str replace -a ' ' "\n" | lines | length

I notice LLMs tend to err on the side of complexity. I don’t know if this is due to their training to spit out as many tokens as possible, but using regular expressions when a simple string replacement may suffice is a good sign that they may be adding more complexity than necessary.