HomeAboutPostsTagsProjectsRSS

Updated
Words403
TagsRead1 minute

Recently discovered Gleam language, and totally fell in love with it shortly!

Here is how you can setup Gleam in doom-emacs

packages.el

We just need the gleam-ts-mode.el, do not download gleam-mode.el as when it gets compiled it requires tree-sitter which causes problem.

(package! gleam-ts-mode
  :recipe (:host github
           :repo "gleam-lang/gleam-mode"
           :branch "main"

           :files ("gleam-ts-*.el")))

config.el

(use-package! gleam-ts-mode
  :config
  ;; setup formatter to be used by `SPC c f`
  (after! apheleia
    (setf (alist-get 'gleam-ts-mode apheleia-mode-alist) 'gleam)
    (setf (alist-get 'gleam apheleia-formatters) '("gleam" "format" "--stdin"))))

(after! treesit
  (add-to-list 'auto-mode-alist '("\\.gleam$" . gleam-ts-mode)))

(after! gleam-ts-mode
  (unless (treesit-language-available-p 'gleam)
    ;; compile the treesit grammar file the first time
    (gleam-ts-install-grammar)))

hack

If you, like me, use Treesitter grammar files from Nix, the tree-sitter subdirectory within the directory specified by user-emacs-directory is linked to Nix’s read-only filesystem, meaning gleam-ts-install-grammar is unable to install grammar files there.

Here’s how you can adjust treesit-extra-load-path and install the grammar file.

(after! gleam-ts-mode
  (setq treesit-extra-load-path (list (expand-file-name "~/.local/tree-sitter/")))
  (unless (treesit-language-available-p 'gleam)
    ;; hack: change `out-dir' when install language-grammar'
    (let ((orig-treesit--install-language-grammar-1 (symbol-function 'treesit--install-language-grammar-1)))
      (cl-letf (((symbol-function 'treesit--install-language-grammar-1)
                 (lambda (out-dir lang url)
                   (funcall orig-treesit--install-language-grammar-1
                            "~/.local/tree-sitter/" lang url))))
        (gleam-ts-install-grammar)))))

Updated
Words37
TagsRead1 minute

Just learned that using [[Emacs]], press C-\ to set input method to TeX, then input Greek symbols will be very easy, for example type \theta will display θ

Here are some frequently used symbols when writing math equations.

symbol
\alphaα
\thetaθ
\delta
Δ
\nabla

Updated
Words440
TagsRead2 minutes

In macOS, I’ve configured a variety of shortcuts to automate tasks, for example:

  • Appending selected text to a specified Obsidian note.
  • Opening a prompt menu and sharing the selected text with ChatGPT to obtain results.
  • Extracting text from an image to read in an editor.
  • And many others.

I frequently use these actions on both my iPhone and Mac. However, on macOS, I find myself having to manually navigate through the Services menu to activate these actions, which tends to slow down my workflow.

To streamline this process, I’ve developed a script that automatically triggers a Services menu item whenever I select text and press Command + Right Click. This enhancement significantly speeds up my interaction with macOS, making my workflow more efficient.

[[Hammerspoon]] script

-- Ensure the listener is global to avoid garbage collection issues
MouseListener = hs.eventtap.new({ hs.eventtap.event.types.rightMouseDown }, function(e)
  local buttonPressed = e:getProperty(hs.eventtap.event.properties.mouseEventButtonNumber)
  local cmdPressed = e:getFlags().cmd

  if cmdPressed == true then
    -- AppleScript to open the Services menu
    -- https://stackoverflow.com/a/59330902/22903883
    hs.osascript.applescript([[
tell application "System Events"
    set appName to item 1 of (get name of processes whose frontmost is true)
    tell (process 1 where frontmost is true)
        tell menu bar 1
            tell menu bar item appName
                tell menu appName
                     tell menu item "Services"
                          tell menu "Services"
                            click menu item "GPT: Share"
                          end tell
                     end tell
                end tell
            end tell
        end tell
    end tell
end tell]])
    return true -- Consume the right-right-click
  end

  return false
end)

-- Start the event listener
MouseListener:start()

Updated
Words613
TagsRead2 minutes

Using lsp-bridge for Language Server Protocol in Emacs

Emacs 29 introduced built-in TRAMP Docker support for editing files within containers. However, enabling auto-completion inside a container remains challenging.

After discovering lsp-bridge , I realized the benefit of a Python process interacting with the language server, rather than relying solely on Emacs Lisp.

I added a feature for automatic reconnection to remote SSH servers and started supporting devcontainers. Using nix-darwin to configure my MacBook, I implemented the devcontainer feature to install lsp-bridge and the language server within the devcontainer. This was facilitated by the Nix ecosystem . To make it work, I needed to start with patching the official Nix devcontainer feature and create separate projects — a long journey, but worthwhile.

Container File Buffer Handling

When opening files in a container, lsp-bridge creates an lsp-bridge buffer, inserts the file content, and uses it for editing and rendering diagnostic information. The remote file content on the container is maintained by the lsp-bridge server running inside the container.

I completed the handling of the visited file modification time for the buffer and enabled auto-revert mode to reload file content automatically when the formatter updates the file.

Using the created lsp-bridge buffer, I used set-visited-file-name to associate a buffer with a file path. However, saving the buffer after the first save prompts a warning: “File has been changed since visited.” This occurs due to discrepancies in how file timestamps are handled by Emacs through TRAMP. To resolve this, Emacs’ record of the file’s modification time must be manually updated with something like this:

(defun my-update-file-mod-time ()
  (when buffer-file-name
    (let ((mod-time (file-attribute-modification-time (file-attributes buffer-file-name))))
      (set-visited-file-modtime mod-time))))

(add-hook 'after-save-hook 'my-update-file-mod-time)

Emacs’ “auto-revert” mode, which automatically reverts buffers when the displayed files change externally, is also useful when files are updated by the formatter. Therefore, the file buffer must enable auto-revert-mode.

With these pieces in place, I now have a smooth editing experience with auto-completion inside the devcontainer.

Emacs rocks!

Updated
Words95
TagsRead1 minute

When taking notes, friction is often a good thing. If it is too easy to create a new note, you don’t write something on your own, but rather just collect information. Consequently, your brain do not process the information, so you learn less from just collecting and reading it. Physical notes have a physical constraint and a limitation on how much we can write on them, but digital notes have no such limitation and rely on self-discipline. So, when taking notes, it is too easy to write too many words. Keep it short and simple.

Updated
Words212
TagsRead1 minute

I use vertico-postframe to place my completion window at the center of screen, however when doing incremental search like doom-emacs SPC s s, it will block the man window.

Here is how to temporarily disable vertico-posframe-mode in Emacs before executing a function, like an incremental search, and then re-enable it afterward.

(defun my-search-without-posframe ()
  "Perform a search without `vertico-posframe-mode' temporarily."
  (interactive)
  ;; Disable vertico-posframe-mode if it's enabled
  (when (bound-and-true-p vertico-posframe-mode)
    (vertico-posframe-mode -1)
    (unwind-protect
        ;; Perform the search
        (call-interactively '+default/search-buffer)
      ;; Re-enable vertico-posframe-mode
      (vertico-posframe-mode 1))))

in config.el

(map! :leader
      :desc "Search without posframe"
      "s s" #'my-search-without-posframe)

Updated
Words234
TagsRead1 minute

different height for Org mode headings

modify only the height of headings in Org mode without affecting other attributes like color

Instead of using custom-theme-set-faces which replaces the whole face definition (and could unintentionally override theme-specific settings like color), use set-face-attribute

doom-emacs config example

(after! org
  ;; Adjust the height of org headings upon org-mode startup
  (add-hook 'org-mode-hook (lambda ()
    (dolist (face '((org-level-1 . 1.75)
                    (org-level-2 . 1.5)
                    (org-level-3 . 1.25)
                    (org-level-4 . 1.1)
                    (org-level-5 . 1.05)
                    (org-level-6 . 1.0)
                    (org-level-7 . 0.95)
                    (org-level-8 . 0.9)))
      (set-face-attribute (car face) nil :height (cdr face)))))

Updated
Words469
TagsRead1 minute

Emacs-obsidian

might be too overkill for me , just opening note in Emacs for intensive editing is enough.

from [[Emacs]]: quickly open Obsidian note

use Deft Mode

from [[Obsidian]]: open current file in Emacs

open file and go to line command for emacsclient to open a.txt at line 4 column 3

emacsclient +4:3 a.txt

use obsidian open current file in emacs

emacsclient -c -s work +{{caret_position}} {{file_path:absolute}}

Use shell-command plugin to create a obsidian command to run the shell command

Updated
Words65
TagsRead1 minute

Posting a markdown document directly to Telegram will display formatting like code blocks and bold text in the message. However, the content received by the Telegram bot differs from what is initially sent, particularly with the removal of backticks.

To send the message content as plain text without formatting, I first paste it into Apple Note on iOS and then share it with the Telegram bot.

Updated
Words482
TagsRead1 minute

Modern Emacs: all those new tools that make Emacs better and faster - YouTube

Optimization

  • Lexical Binding: Before Emacs 24 emacs-lisp is dynamic binding. lexical binding is introduced in Emacs 24, enabling compile-time optimizations.
  • Native Compilation: Introduced in Emacs 28, native compilation used the GCC JIT compile to convert Emacs Lisp code to native machine code, dramatically improving execution speed.

Package Management

  • Lazy loading with use-package: use-package is now build into Emacs 29
  • Straight Package Manager : works with use-package to handle package installations and version control.

Syntax Highlighting and Parsing

  • Tree-sitter Integration: Emacs 29 includes support for Tree-sitter, a parser generator that improves syntax highlighting and code navigation by using precise parse trees instead of regular expressions. This results in more accurate and faster syntax highlighting.
  • tree-sitter mode: new major modes that utilize tree-sitter for enhanced code parsing and highlighting, for example, use python-ts-mode to replace traditional python-mode.

Completion Frameworks

  • Historical Context: Initially, Emacs used ido for interactive file and buffer navigation, followed by heavier frameworks like helm and ivy for more advanced completions.
  • Modern Solutions: vertico consult orderless marginalia embark

Language Server Protocol (LSP)

  • eglot: Emacs’ build-in LSP client

I personally use lsp-bridge for completion and LSP