Kamyab's Blog

~/ github mail

Python Syntax Highlight Test

A quick post to test syntax highlighting with Python code.

Basic example

def greet(name: str) -> str:
    return f"Hello, {name}!"

print(greet("world"))

Something slightly more interesting

import os
from pathlib import Path

def find_large_files(directory: str, threshold_mb: float = 10.0) -> list[Path]:
    """Return files larger than threshold_mb in the given directory."""
    threshold = threshold_mb * 1024 * 1024
    results = []

    for path in Path(directory).rglob("*"):
        if path.is_file() and path.stat().st_size > threshold:
            results.append(path)

    return sorted(results, key=lambda p: p.stat().st_size, reverse=True)

if __name__ == "__main__":
    large = find_large_files(os.getcwd())
    for f in large:
        size_mb = f.stat().st_size / (1024 * 1024)
        print(f"{size_mb:.1f} MB  {f}")

چرا از امکس استفاده می‌کنم

امکس برای من فقط یک ویرایشگر متن نیست. بیشتر شبیه یک محیط کامل برای کار روزمره‌ام است.

مشکل اولیه

وقتی اول شروع کردم، مثل خیلی‌ها از VSCode استفاده می‌کردم. سریع بود، پلاگین داشت، کار می‌کرد. ولی هر بار که می‌خواستم چیز خاصی انجام بدم، یا پلاگین مناسب نبود یا رفتارش دقیقاً آنطور که می‌خواستم نبود.

چرا امکس؟

امکس با Emacs Lisp قابل تنظیم است. یعنی اگر چیزی را دوست نداری، می‌توانی تغییرش بدهی. نه workaround، نه تنظیمات JSON، بلکه کد واقعی.

(defun my/open-notes ()
  "باز کردن فایل یادداشت‌های روزانه"
  (interactive)
  (find-file "~/notes/today.org"))

(global-set-key (kbd "C-c n") #'my/open-notes)

این تابع ساده‌ای است که من هر روز ازش استفاده می‌کنم. دو خط کد، یک میانبر کیبورد، تمام.

org-mode

بزرگترین دلیل ماندنم org-mode است. برنامه‌ریزی، یادداشت‌برداری، نوشتن پست‌های همین سایت، همه در org-mode انجام می‌شود. حتی این پست را با org-mode نوشتم.

Docker Find File

I regularly need to view/edit/manipulate files in a Docker container that are not mounted from the outside. It sure is nice to do that from the comfort of Emacs.

My desired behavior was a this:

  1. invoke a function
  2. see a list of running containers and select one
  3. find file or directory from that container

docker.el can be used for interacting with the Docker API. For the second step, I use ivy/counsel as my completion framework but anything works, really. For the final and most important step, there's the almighty TRAMP.

I have a function for listing containers, which is just a wrapper around docker.el functions.

(defun kz/docker-container-entries (&rest filters)
  (if (and filters (car filters))
      (aio-wait-for
       (docker-container-entries
        (mapconcat (lambda (f) (format "-f %s" f)) filters " "))))
  (aio-wait-for (docker-container-entries "--all")))

This will synchronously call docker-container-entries (from docker.el), with provided filters.

What I didn't know and learned while trying to do this, was the completing-read function. I used it all the time, but not in my own functions. Here's the documentation. ivy (and alternatives) make this "minibuffer completions" smoother.

(completing-read "Select container: " (kz/docker-container-entries "status=running"))

If I need to open, for example, /etc/nginx/nginx.conf from nginx-container, using TRAMP, I could write:

(find-file "/docker:root@nginx-container:/etc/nginx/nginx.conf")

For my purpose, since I want a more interactive experience, I will use counsel-find-file and pass it the prefix /docker:root@container:/ to make my life easier. This is the final product:

(defun kz/docker-find-file ()
  (interactive)
  (let ((container (completing-read "Select container: " (kz/docker-container-entries "status=running"))))
    (counsel-find-file (concat "/docker:root@" container ":/"))))