Skip to content

amadev/emacs-conf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 

Repository files navigation

emacs

Installation

Build emacs example on Ubuntu 22.04.

sudo cp /etc/apt/sources.list /etc/apt/sources.list~

sudo sed -Ei ‘s/^# deb-src /deb-src /’ /etc/apt/sources.list

sudo apt-get update

sudo apt-get build-dep emacs

gcc –version

sudo apt-get install libgccjit0 libgccjit-11-dev

cd ~/s/

wget https://ftpmirror.gnu.org/emacs/emacs-28.2.tar.xz

ls -lh emacs-28.2.tar.xz

tar -xvf emacs-28.2.tar.xz

rm emacs-28.2.tar.xz

mv emacs-28.2 emacs

du -sh emacs

cd emacs

(compile “(cd home/amadev/s/emacs; ./autogen.sh)”)

(compile “(cd home/amadev/s/emacs; ./configure –with-native-compilation)”)

(compile “(cd home/amadev/s/emacs; make)”)

/home/amadev/s/emacs/src/emacs –batch –eval ‘(native-comp-available-p)’

Запуск и внешний вид

Запускаю emacs из консоли, при этом скрин наследует переменные окружения, а именно ssh-agent.

Конфигурация создается через tangle всех исходников описанных ниже. Для создания файла org-babel-tangle c-c c-v t.

(require 'package)
(add-to-list 'package-archives
             '("melpa" . "https://melpa.org/packages/"))

(setq not-linux (memq window-system '(mac ns)))
(setq mu4e-enabled nil)
(when not-linux
  (package-initialize)
  (setq mu4e-enabled nil))

Для меня удобнее, когда я вижу одно окно, не отвлекаясь на дополнительные приложения. В один момент времени выполняю одну функцию. Убираем лишние GUI-свистелки.

(tooltip-mode -1)
(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)
(setq ring-bell-function 'ignore)

Отключаю пригласительный экран и текст в скретч.

(setq inhibit-startup-screen t
      initial-scratch-message nil)
(setenv "LANG" "en_US.UTF-8")
(setq system-time-locale "C")

Размер шрифта, тема. Другие темы warm-night, brutalist-dark, blackboard, clues, anti-zenburn.

(set-face-attribute 'default nil :height 130)
(load-theme 'zenburn t)
(set-cursor-color "#909090")

Разбивать окна вертикально.

;; may split a window horizontally only if it has at least this many columns
(setq split-width-threshold 200)
(setq split-height-threshold nil)

Disable version control to speed up TRAMP opening.

(setq vc-handled-backends ())

Бекап создается при первом сохранении буфера. Авто-сейв после 30 сек или 300 символов. Сохраняемые файлы вынес в отдельную папку, чтобы не гадить в рабочей директории. Используем версии бекапных файлов и делаем бекапы файлов, которые под контролем версий (git, svn).

(setq backup-directory-alist '(("." . "~/.emacs.d/backups")))
(setq auto-save-file-name-transforms '((".*" "~/.emacs.d/auto-save-list/" t)))
(setq version-control t)
(setq vc-make-backup-files t)
(setq delete-old-versions -1)

Don’t type yes.

(fset 'yes-or-no-p 'y-or-n-p)

Performance

Show startup time.

(add-hook 'emacs-startup-hook
          (lambda ()
            (message "Emacs ready in %s with %d garbage collections."
                     (format "%.2f seconds"
                             (float-time
                              (time-subtract after-init-time before-init-time)))
                     gcs-done)))

Measure some code running time.

(defmacro measure-time (label &rest body)
  "Measure the time it takes to evaluate BODY."
  `(let ((time (current-time)))
     ,@body
     (message "%s time %.06f" ,label (float-time (time-since time)))))

GC

(setq gc-cons-threshold 100000000)

helm

http://tuhdo.github.io/helm-intro.html

(use-package helm
  :init
  (setq helm-split-window-in-side-p t)
  (setq helm-M-x-fuzzy-match t)
  (defun helm-old-ff (&optional no-op)
    (interactive)
    (call-interactively 'find-file))

  :bind
  (("C-x f" . helm-projectile)
   ("C-x C-f" . find-file-at-point)
   ("C-x C-b" . helm-mini)
   ("M-y" . helm-show-kill-ring)
   ("M-x" . helm-M-x)
   ("C-h SPC". helm-all-mark-rings)
   ([remap man] . helm-man-woman)
   ;; Fallback to old find-file mode for tramp.
   (:map helm-map
         ("C-f" . (lambda ()
                    (interactive)
                    (helm-quit-and-execute-action 'helm-old-ff))))))

Prog

Add magit.

(use-package magit)

Display current python buffer structure.

(defun occur-python-structure ()
  (interactive)
  (occur "def\\b\\|class\\b\\|=[ ]?lambda"))

Grep something under cursor.

(defun grep-at-point ()
  (interactive)
  (let ((s (thing-at-point 'symbol t)))
    (ack (concat "ag -i --nogroup --nocolor " s " --ignore tests")
         (ack-default-directory 4))))

LSP mode.

go install golang.org/x/tools/gopls@latest

pip install python-lsp-server[all] python-lsp-black

(use-package lsp-mode
  :init
  (setq lsp-keymap-prefix "C-c l")
  :hook
  (
   (python-mode . lsp)
   (go-mode . lsp)
   (lsp-mode . lsp-enable-which-key-integration)
   )
  )

(use-package helm-lsp :commands helm-lsp-workspace-symbol)

(use-package which-key
    :config
    (which-key-mode))

Глобальные функции

History and backups

Comint history

(use-package comint
  :config
  (setq
   comint-input-ring-size 200000
   comint-scroll-show-maximum-output t
   comint-input-ignoredups t
   comint-input-ring-separator "$$$\n"))

To write history manually just issue: (comint-write-input-ring) (comint-read-input-ring)

See https://oleksandrmanzyuk.wordpress.com/2011/10/23/a-persistent-command-history-in-emacs/.

(defun turn-on-comint-history ()
  (let ((process (get-buffer-process (current-buffer))))
    (when process
      (setq comint-input-ring-file-name
            (format (with-home-dir ".emacs.d/history.d/%s-buffer-history")
                    (buffer-name (current-buffer))))
      (comint-read-input-ring)
      (set-process-sentinel process #'comint-write-history-on-exit))))
(defun comint-write-input-ring-before-output (str)
  (if str (comint-write-input-ring))
  str)

(add-hook 'comint-preoutput-filter-functions
          'comint-write-input-ring-before-output)
(defun comint-write-history-on-exit (process event)
  (comint-write-input-ring)
  (let ((buf (process-buffer process)))
    (when (buffer-live-p buf)
      (with-current-buffer buf
        (insert (format "\nProcess %s %s" process event))))))

Enable comint history for the specific modes.

(add-hook 'shell-mode-hook 'turn-on-comint-history)
(add-hook 'inferior-python-mode-hook 'turn-on-comint-history)
(add-hook 'inferior-emacs-lisp-mode-hook 'turn-on-comint-history)

Save history for comint buffers history on kill or Emacs closing.

(require 'comint)
(add-hook 'kill-buffer-hook 'comint-write-input-ring)

(defun mapc-buffers (fn)
  (mapc (lambda (buffer)
          (with-current-buffer buffer
            (funcall fn)))
        (buffer-list)))

(defun comint-write-input-ring-all-buffers ()
  (mapc-buffers 'comint-write-input-ring))

(add-hook 'kill-emacs-hook 'comint-write-input-ring-all-buffers)

Helm comint history.

(defun shell-mode-custom-keys ()
  (local-set-key (kbd "M-r") 'helm-comint-input-ring))

(add-hook 'shell-mode-hook 'shell-mode-custom-keys)
(require 'yaml-mode)
(require 'comint)

(defvar comint-history-file "~/.emacs.d/history.d/comint-history-%Y-%m-%d.log"
  "File where comint input/output history is stored.")

(defun remove-ansi-escape-sequences (string)
"Remove ANSI escape sequences from STRING."
(replace-regexp-in-string "\033\\[[0-9;]*[mK]" "" string))

(defun comint-log-to-file (type content)
  "Log the TYPE (either 'input or 'output) and CONTENT to the comint history file."

  (if (> (length content) 0)
      (let ((cbuffer (current-buffer))
            (history-file (format-time-string comint-history-file (current-time))))
        (with-temp-buffer
          ;; (when (file-exists-p history-file)
          ;;   (insert-file-contents history-file))
          (goto-char (point-max))
          (let ((timestamp (format-time-string "%Y-%m-%d %H:%M:%S"))
                (inhibit-message t)
                (message-log-max nil))
            (insert (format "- %s: %s\n  buffer: %s\n  timestamp: %s\n  content: |-\n    %s\n\n"
                            "direction" (if (eq type 'input) "input" "output")
                            cbuffer
                            timestamp
                            (replace-regexp-in-string "\n" "\n    " content))))
          (write-region (point-min) (point-max) history-file t 1)))))

(defun comint-log-input (input)
  "Function to log comint input."
  (comint-log-to-file 'input input)
  input)

(defun comint-log-output (output)
  "Function to log the first 2000 characters of comint output."
  (let ((trimmed-output (if (> (length output) 2000)
                            (substring output 0 2000)
                          output)))
    (comint-log-to-file 'output (remove-ansi-escape-sequences trimmed-output)))
  output)

(add-hook 'comint-input-filter-functions 'comint-log-input)
(add-hook 'comint-output-filter-functions 'comint-log-output)

Минибуфер

Работает автоматически, при загрузке emacs подгружается история. Для просмотра истории helm-minibuffer-history.

(setq savehist-file "~/.emacs.d/history.d/minibuffer-history")
(savehist-mode t)
(setq history-length 20000)
(setq history-delete-duplicates t)
(setq savehist-save-minibuffer-history 1)
(setq savehist-additional-variables
      '(kill-ring
        search-ring
        regexp-search-ring))

Поиск

По умолчанию запускаем поиск regexp.

(global-set-key (kbd "C-s") 'isearch-forward-regexp)
(global-set-key (kbd "C-r") 'isearch-backward-regexp)
(global-set-key (kbd "C-M-s") 'isearch-forward)
(global-set-key (kbd "C-M-r") 'isearch-backward)

Для поиска символа под курсором можно воспользоваться (isearch-forward-symbol-at-point) M-s . либо дополнительной функцией в режиме поиска.

(define-key isearch-mode-map (kbd "C-*")
  (lambda ()
    "Reset current isearch to a word-mode search of the word under point."
    (interactive)
    (setq isearch-word t
          isearch-string ""
          isearch-message "")
    (isearch-yank-string (word-at-point))))

Полезные сочетания в режиме поиска: М-r - переключение regexp, M-c - перечлючение case sensitive, M-e - редактирование.

Из поска можно переключаться на замену: M-S %. Это удобно, что можно подсветить фрагмент поиска и найти, то что нужно интерактивно, а затем заменить.

В поиске можно использовать выражения, например: :\([0-9]+\) → =\1

(use-package anzu
   :ensure t
   :init (global-anzu-mode -1))

Удалениие пробелов вначале и конце строки.

(defun chomp (str)
      "Chomp leading and tailing whitespace from STR."
      (while (string-match "\\`\n+\\|^\\s-+\\|\\s-+$\\|\n+\\'"
                           str)
        (setq str (replace-match "" t t str)))
      str)

Получение пароля происходит через консольную команду

Пароли

(defun get-pass (name)
  (let ((cname (if (symbolp name) (symbol-name name) name)))
    (chomp (shell-command-to-string (concat "cpp.sh " cname)))))

Пути от домашней папки и emacs.d.

(defun may-be-add-first-slash (path)
  (concat (if (string-match "^/" path) "" "/") path))

(defun with-home-dir (path)
  (concat (expand-file-name "~") (may-be-add-first-slash path)))

(defun with-emacs-dir (path)
  (with-home-dir (concat ".emacs.d" (may-be-add-first-slash path))))

Копирование имени файла текущего буфера в clipboard.

(defun copy-file-name-to-clipboard ()
  "Copy the current buffer file name to the clipboard."
  (interactive)
  (let ((filename (if (equal major-mode 'dired-mode)
                      default-directory
                    (buffer-file-name))))
    (when filename
      (kill-new filename)
      (message "Copied buffer file name '%s' to the clipboard." filename))))

Русская раскладка С-\

(load-file "~/.emacs.d/cyrillic-dvorak.el")
(setq default-input-method "cyrillic-dvorak")

Шаблоны

Включаем возможность использования шаблонов везде. Личные шаблоны храняться в file:///~/.emacs.d/snippets/. Шаблоны могут использоваться как по ключу (key), так и по сочетанию клавиш (binding), последнее полезно для оборачивания региона шаблоном. yas-wrap-around-region включает такое поведение.

(use-package yasnippet
  :ensure t
  :config
  (defun yas/org-very-safe-expand ()
    (let ((yas/fallback-behavior 'return-nil)) (yas/expand)))

  (add-hook 'org-mode-hook
            (lambda ()
              (make-variable-buffer-local 'yas/trigger-key)
              (setq yas/trigger-key [tab])
              (add-to-list 'org-tab-first-hook 'yas/org-very-safe-expand)
              (define-key yas/keymap [tab] 'yas/next-field)))

  (setq
   yas-verbosity 1
   yas-wrap-around-region t
   yas-snippet-dirs (append yas-snippet-dirs
                               '("/home/amadev/.emacs.d/snippets"))
   )

  (yas-reload-all)
  ;; (yas-global-mode)
  )

(use-package yasnippet-snippets         ; Collection of snippets
  :ensure t)

Браузер

(setq browse-url-browser-function 'browse-url-generic
     browse-url-generic-program "firefox")

(when (eq system-type 'darwin)
  (setq browse-url-generic-program "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"))

Смена сплита буферов вертикальный/горизонтальный

(defun toggle-window-split ()
  (interactive)
  (if (= (count-windows) 2)
      (let* ((this-win-buffer (window-buffer))
	     (next-win-buffer (window-buffer (next-window)))
	     (this-win-edges (window-edges (selected-window)))
	     (next-win-edges (window-edges (next-window)))
	     (this-win-2nd (not (and (<= (car this-win-edges)
					 (car next-win-edges))
				     (<= (cadr this-win-edges)
					 (cadr next-win-edges)))))
	     (splitter
	      (if (= (car this-win-edges)
		     (car (window-edges (next-window))))
		  'split-window-horizontally
		'split-window-vertically)))
	(delete-other-windows)
	(let ((first-win (selected-window)))
	  (funcall splitter)
	  (if this-win-2nd (other-window 1))
	  (set-window-buffer (selected-window) this-win-buffer)
	  (set-window-buffer (next-window) next-win-buffer)
	  (select-window first-win)
	  (if this-win-2nd (other-window 1))))))

Смена содержимого окон

(defun swap-windows (arg)
  "Transpose the buffers shown in two windows."
  (interactive "p")
  (let ((selector (if (>= arg 0) 'next-window 'previous-window)))
    (while (/= arg 0)
      (let ((this-win (window-buffer))
            (next-win (window-buffer (funcall selector))))
        (set-window-buffer (selected-window) next-win)
        (set-window-buffer (funcall selector) this-win)
        (select-window (funcall selector)))
      (setq arg (if (plusp arg) (1- arg) (1+ arg))))))

Аккорды

Назначаем сочетания символов на часто используемые функции.

(require 'key-chord)
(key-chord-mode 1)
(key-chord-define-global "yy" 'ack)
(key-chord-define-global "jj" 'ace-jump-mode)
(key-chord-define-global "hh" 'magit-status)

Работа c unicode

Часто используемые символы удобно смотреть: http://xahlee.info/comp/unicode_index.html http://www.unexpected-vortices.com/doc-notes/some-common-unicode-characters.html Вставка c-x 8 ret.

Spell checking

Для проверки можно использовать flyspell-region или ispell-region, также можно влючить проверку для mode через mode-hook (flyspell-mode).

http://endlessparentheses.com/ispell-and-org-mode.html

M-$ - исправление первого слова с ошибкой после курсора. В сессии исправления можно принять текущее слова (a/A),

добавить в личный словарь (i).

Переключение словаря - ispell-change-dictionary.

Magit for project

(use-package magit
  :ensure t)

(defun magit-nova ()
  (interactive)
  (let ((buffer "magit: nova"))
    (if (get-buffer buffer)
	(switch-to-buffer "magit: nova")
      (magit-status "~/m/nova"))))

(global-set-key (kbd "C-; n") 'magit-nova)

defaults

(require 'uniquify)
(setq uniquify-buffer-name-style 'forward)

(require 'saveplace)
(setq-default save-place t)

(global-set-key (kbd "M-/") 'hippie-expand)
(global-set-key (kbd "C-x C-b") 'ibuffer)

(use-package ace-window
  :ensure t
  :init (global-set-key [remap other-window] 'ace-window))

(require 'expand-region)
(global-set-key (kbd "C-=") 'er/expand-region)

(global-set-key (kbd "M-n") 'delete-indentation)

(show-paren-mode 1)

;; show buffer file path or buffer name
(setq frame-title-format '(buffer-file-name "emacs %f" ("emacs %b")))

;; NO TABS, spaces only
(setq-default indent-tabs-mode nil)
(setq tab-width 4)

(setq find-program "find")

(setq x-select-enable-clipboard t
      x-select-enable-primary t
      save-interprogram-paste-before-kill t
      apropos-do-all t
      mouse-yank-at-point t
      save-place-file (concat user-emacs-directory "places")
      Info-additional-directory-list '("/usr/share/info/emacs-snapshot/" "/usr/local/share/info"))

(setq tramp-default-method "ssh")

(use-package ack
  :ensure t
  :init (setq
         ack-defaults-function 'ack-legacy-defaults
         ack-command "ag -i --nogroup --nocolor ")
  :config (defalias 'grep 'ack))

(setq grep-command "ag -i --nogroup --nocolor ")

(require 'inline-string-rectangle)

(defun fc-eval-and-replace ()
  "Replace the preceding sexp with its value."
  (interactive)
  (backward-kill-sexp)
  (condition-case nil
      (prin1 (eval (read (current-kill 0)))
             (current-buffer))
    (error (message "Invalid expression")
           (insert (current-kill 0)))))

(display-time-mode t)

(add-hook 'before-save-hook 'delete-trailing-whitespace)

(global-set-key (kbd "C-w") 'clipboard-kill-region)
(global-set-key (kbd "M-w") 'clipboard-kill-ring-save)
(global-set-key (kbd "C-y") 'clipboard-yank)
(global-set-key (kbd "C-x r t") 'inline-string-rectangle)
(global-set-key (kbd "C-<") 'mark-previous-like-this)
(global-set-key (kbd "C->") 'mark-next-like-this)

(custom-set-faces
 '(which-func ((t (:foreground "#b680b1" :weight bold))))
 '(chess-ics1-black-face ((t (:foreground "dim gray" :weight bold))))
 '(chess-ics1-white-face ((t (:foreground "chocolate" :weight bold))))
 '(secondary-selection ((t (:background "olive drab")))))

(put 'narrow-to-region 'disabled nil)
(put 'downcase-region 'disabled nil)

(setq helm-locate-project-list '("~/m/nova"))

(setq ix-user "amadev"
      ix-token (get-pass "ix.io"))

(setq fill-column 80)

(setq create-lockfiles nil)

text

(defun rows2one (start end)
  (interactive "r")
  (save-restriction
    (narrow-to-region start end)
    (goto-char (point-min))
    (replace-regexp "^" "'")
    (goto-char (point-min))
    (replace-regexp "$" "',")
    (goto-char (point-min))
    (while (search-forward "\n" nil t) (replace-match " " nil t))
    (move-end-of-line)
    ))

(defun pretty-print-xml-region (begin end)
  "Pretty format XML markup in region. You need to have nxml-mode
http://www.emacswiki.org/cgi-bin/wiki/NxmlMode installed to do
this. The function inserts linebreaks to separate tags that have
nothing but whitespace between them. It then indents the markup
by using nxml's indentation rules."
  (interactive "r")
  (save-excursion
    (goto-char begin)
    (while (search-forward-regexp "\>[ \\t]*\<" nil t)
      (backward-char) (insert "\n") (setq end (1+ end)))
    (indent-region begin end))
  (message "Ah, much better!"))

(defun duplicate-line(arg)
  "Duplicate current line, leaving point in lower line."
  (interactive "*p")

  ;; save the point for undo
  (setq buffer-undo-list (cons (point) buffer-undo-list))

  ;; local variables for start and end of line
  (let ((bol (save-excursion (beginning-of-line) (point)))
        eol)
    (save-excursion

      ;; don't use forward-line for this, because you would have
      ;; to check whether you are at the end of the buffer
      (end-of-line)
      (setq eol (point))

      ;; store the line and disable the recording of undo information
      (let ((line (buffer-substring bol eol))
            (buffer-undo-list t)
            (count arg))
        ;; insert the line arg times
        (while (> count 0)
          (newline)         ;; because there is no newline in 'line'
          (insert line)
          (setq count (1- count)))
        )

      ;; create the undo information
      (setq buffer-undo-list (cons (cons eol (point)) buffer-undo-list)))
    ) ; end-of-let

  ;; put the point in the lowest line and return
  (next-line arg))

(global-set-key (kbd "C-c l") 'duplicate-line)

(defvar current-date-time-format "%Y-%m-%dT%T%z"
  "Format of date to insert with `insert-current-date-time' func
See help of `format-time-string' for possible replacements")

(defvar current-time-format "%H:%M:%S%z"
  "Format of date to insert with `insert-current-time' func.
Note the weekly scope of the command's precision.")

(defun insert-current-date-time ()
  "insert the current date and time into current buffer.
Uses `current-date-time-format' for the formatting the date/time."
       (interactive)
       (insert (format-time-string current-date-time-format (current-time))))

(defun insert-current-date ()
  "insert the current date and time into current buffer.
Uses `current-date-time-format' for the formatting the date/time."
       (interactive)
       (insert (format-time-string "%Y-%m-%d" (current-time))))

(defun insert-current-time ()
  "insert the current time (1-week scope) into the current buffer."
       (interactive)
       (insert (format-time-string current-time-format (current-time))))

(defun sentence-from-func-name-in-string (func-name)
  (let ((splitted-fn (split-string func-name "_")))
    (setf (first splitted-fn) (capitalize (first splitted-fn)))
    (concat (mapconcat 'identity splitted-fn " ") "."))
  )

(defun sentence-from-func-name (start end)
  (interactive "r")
  (let ((result
         (sentence-from-func-name-in-string
          (buffer-substring-no-properties start end))))
    (save-excursion
      (delete-region start end)
      (goto-char start)
      (insert result))))

prog

(defun my-prog-mode-hook ()
  (setq whitespace-style '(face lines-tail trailing)
        whitespace-line-column 79)
  (whitespace-mode t)
  (which-function-mode t)
  (idle-highlight-mode t)
  (make-local-variable 'column-number-mode)
  (column-number-mode t)
  (hl-line-mode t)
  (add-to-list 'write-file-functions 'delete-trailing-whitespace)
  (yas-minor-mode)
  )

(add-hook  'prog-mode-hook 'my-prog-mode-hook)

(defun shell-yasnippet ()
  (yas-minor-mode)
  )

(add-hook  'shell-mode-hook 'shell-yasnippet)

Макросы

kmacro-name-last-macro insert-kbd-macro

(fset 'convert_shell_env_to_emacs
      (lambda (&optional arg)
        "Keyboard macro."
        (interactive "p")
        (kmacro-exec-ring-item
         (quote ([40 4 115 101 116 101 110 118 32 34 4 19 61 return backspace 34 32 34 4 5 34 41 14 1] 0 "%d")) arg)))

(fset 'pytest-args-from-test-name
   (lambda (&optional arg) "Keyboard macro." (interactive "p") (kmacro-exec-ring-item '([134217765 46 return 47 return 33 backspace 32 45 107 32 18 47 return 67108896 19 32 23 2 2 2 23 46 112 121 5] 0 "%d") arg)))

(fset 'create-a-drill
   (kmacro-lambda-form [?* ?* ?* ?* backspace ?  ?\C-s ?  ?- ?  return backspace backspace backspace return backspace backspace backspace backspace ?* ?* ?* ?* ?  ?a ?n ?s ?w ?e ?r ?  backspace return backspace backspace backspace backspace backspace ?\C-p ?\C-p ?\C-c ?\C-q ?d ?r ?i ?l ?l return ?\C-e return backspace backspace backspace backspace ?t ?r ?a ?n ?s ?l ?a ?t ?e ?\C-n ?\C-n ?\C-n ?\C-a] 0 "%d"))

Replace multiple empty lines with a single one

(defun single-lines-only ()
  "replace multiple blank lines with a single one"
  (interactive)
  (goto-char (point-min))
  (while (re-search-forward "\\(^\\s-*$\\)\n" nil t)
    (replace-match "\n")
    (forward-char 1)))

Export presentations to site

(require 'ox-reveal)
(defun my-export ()
  (interactive)
  (save-current-buffer
    (let ((org-reveal-width 1920)
          (org-reveal-height 1080))
     (set-buffer "scheduler.org")
     (org-reveal-export-to-html)))
  (shell-command-to-string "scp -r ~/org/scheduler amadev:~/www/docs/")
  (shell-command-to-string "scp ~/org/scheduler.html amadev:~/www/docs/")
  (shell-command-to-string "scp ~/org/custom.css amadev:~/www/docs/reveal.js/css/")
  (shell-command-to-string "rm ~/org/scheduler.html"))

Delete buffes by name

Using ibuffer it can be done with marking buffers by name with ‘% n’ and press ‘D’ after that.

Color codes

(use-package ansi-color
  :init
  (defun display-ansi-colors ()
    (interactive)
    (ansi-color-apply-on-region (point-min) (point-max))))

git-link

(use-package git-link
  :config
  (defun git-link-mcp (hostname dirname filename branch commit start end)
    (format "https://gerrit.mcp.mirantis.com/gitweb?p=%s.git;a=blob;f=%s;hb=refs/heads/%s%s"
	    dirname
            filename
            branch
	    (when start
              (concat "#"
                      (if end
                          (format "l%s-l%s" start end)
                        (format "l%s" start))))))

  (add-to-list 'git-link-remote-alist '("gerrit.mcp.mirantis.net" git-link-mcp))

  (defun git-link-openstack (hostname dirname filename branch commit start end)
    (format "https://git.openstack.org/cgit/%s/tree/%s?h=refs/heads/%s%s"
	    dirname
            filename
            branch
	    (when start
              (concat "#"
                      (if end
                          (format "n%s-n%s" start end)
                        (format "n%s" start))))))

  (defun git-link-openstack-github (hostname dirname filename branch commit start end)
    (funcall 'git-link-github "github.com" dirname filename branch commit start end))

  (defun git-link-commit-openstack-github (hostname dirname commit)
    (funcall 'git-link-commit-github "github.com" dirname commit))

  ;; (add-to-list 'git-link-remote-alist '("review.openstack.org" git-link-openstack))
  (add-to-list 'git-link-remote-alist '("review.openstack.org" git-link-openstack-github))
  (add-to-list 'git-link-commit-remote-alist '("review.openstack.org" git-link-commit-openstack-github))
  )

Script wrappers

(setq vpn-name "forcode")
(setq vpn-name "surfshark")

(defun kill-vpn ()
  (interactive)
  (shell-command-to-string "ps -eF | grep openvpn | grep -v grep | head -n1 | awk '{print $2}' | sudo xargs kill")
  )

(defun run-vpn ()
  (interactive)
  (kill-vpn)
  (start-process "vpn" "vpn-buffer" (format "/home/amadev/bin/run_%s_vpn" vpn-name))
  )

(defun myip ()
  (interactive)
  (message (shell-command-to-string "ip=$(curl -s ifconfig.me); echo $ip \\($(curl -s ipinfo.io/$ip| jq -r .country)\\)"))
  )

Send region to comint buffer

Send buffer string to the shell specified by name in target-shell-session. It could be defined as file local variable:

(require 'subr-x)

(make-variable-buffer-local
 (defvar target-shell-session "shell-default"
   "Name of session buffer for sending comands from sh-send-mode"))

(defun send-current-paragraph-or-region (&optional step cmd)
  (interactive ())

  (let* ((pbuf (get-buffer target-shell-session))
         (proc (get-buffer-process pbuf))
         min max command)
    (if (use-region-p)
        (setq min (region-beginning)
              max (region-end))
      (setq min (save-excursion (backward-paragraph) (point))
            max (save-excursion (re-search-forward "\n[\t\n ]*\n+" nil "NOERROR") (point))))
    (setq command (if cmd
                      cmd
                    (concat (string-trim (buffer-substring min max)) "\n")))
    ;; (message "sending '%s'  to '%s'" command target-shell-session)
    (if (and (derived-mode-p 'org-mode) (string-prefix-p "- [" (string-trim (thing-at-point 'line t))))
        (org-ctrl-c-ctrl-c)
        (progn (with-current-buffer pbuf
           (goto-char (process-mark proc))
           (insert command)
           (comint-send-input))
         (display-buffer (process-buffer proc) t)
         (when step
           (goto-char max)
           (next-line))))))

(defun send-current-paragraph-or-region-and-step ()
  (interactive)
  (send-current-paragraph-or-region t))

(defun switch-to-process-buffer ()
  (interactive)
  (pop-to-buffer (get-buffer target-shell-session) t))

(defun sh-set-to-current-dir ()
  (interactive)
  (send-current-paragraph-or-region nil (concat "cd " default-directory)))

(define-minor-mode sh-send-mode
  "Send a paragraph or marked string to the shell buffer."
  :lighter " ss"
  :keymap (let ((map (make-sparse-keymap)))
            (define-key map (kbd "C-c C-c") 'send-current-paragraph-or-region-and-step)
            (define-key map (kbd "C-c C-z") 'switch-to-process-buffer)
            map))

(add-hook 'sh-mode-hook 'sh-send-mode)
(add-hook 'sql-mode-hook 'sh-send-mode)
(add-hook 'clojure-mode-hook 'sh-send-mode)
(add-hook 'org-mode-hook 'sh-send-mode)

Smartparens

Example config: https://github.com/Fuco1/.emacs.d/blob/master/files/smartparens.el

(use-package smartparens-config
  :ensure smartparens
  :init (setq sp-base-key-bindings 'paredit)
  :config (progn
            (show-smartparens-global-mode t))
  :bind
  (:map smartparens-mode-map
        ("C-<right>" . sp-forward-slurp-sexp)
        ("C-<left>" . sp-forward-barf-sexp)
        ("C-c <left>" . sp-backward-slurp-sexp)
        ("C-c <right>" . sp-backward-barf-sexp)
        ("C-M-f" . sp-forward-sexp)
        ("C-M-b" . sp-backward-sexp)
        ("M-r" . sp-raise-sexp)
        ))

(add-hook 'prog-mode-hook 'turn-on-smartparens-strict-mode)
(add-hook 'markdown-mode-hook 'turn-on-smartparens-strict-mode)
(add-hook 'cider-repl-mode-hook 'turn-on-smartparens-strict-mode)

Shell track current dir

(defun shell-procfs-dirtrack (str)
  (prog1 str
    (when (string-match comint-prompt-regexp str)
      (let ((directory (file-symlink-p
                        (format "/proc/%s/cwd"
                                (process-id
                                 (get-buffer-process
                                  (current-buffer)))))))
        (when (file-directory-p directory)
          (cd directory))))))

(define-minor-mode shell-procfs-dirtrack-mode
  "Track shell directory by inspecting procfs."
  nil nil nil
  (cond (shell-procfs-dirtrack-mode
         (when (bound-and-true-p shell-dirtrack-mode)
           (shell-dirtrack-mode 0))
         (when (bound-and-true-p dirtrack-mode)
           (dirtrack-mode 0))
         (add-hook 'comint-preoutput-filter-functions
                   'shell-procfs-dirtrack nil t))
        (t
         (remove-hook 'comint-preoutput-filter-functions
                      'shell-procfs-dirtrack t))))

Docker

(use-package dockerfile-mode :ensure t)

Работа с файлами dired

Для просмотра содержимого папки можно C-x C-f C-f, либо C-x d, для второго варианта можно указать glob-шаблон, чтобы отфильтровать нужное, например *.org.

Сортировка по дате/алфавиту - s. Задание переключателей для ls - C-u s, можно указать h, чтобы видеть размеры в человекопонятном виде.

Режим wdired позволяет изменять имена файлов, как текст C-x C-q.

Пометка файлов через regexp - % m. Выделить все - * s. Инвертировать выделение - * t.

Скопировать, переместить, удалить - C, R, D.

Скопировать полный путь до файла C-u 0 w.

Настройки отображения dired по умолчанию. Показываем все, сортируем по дате (новые внизу), но сначала директории.

(setq dired-listing-switches "-altrh  --group-directories-first")

Использовать lisp-версию ls для Mac.

(when (eq system-type 'darwin)
  (require 'ls-lisp)
  (setq ls-lisp-use-insert-directory-program nil))
(use-package dired-subtree :ensure t
  :after dired
  :config
  (bind-key "<tab>" #'dired-subtree-toggle dired-mode-map)
  (bind-key "<backtab>" #'dired-subtree-cycle dired-mode-map))

(use-package dired-git-info
    :ensure t
    :bind (:map dired-mode-map
                (")" . dired-git-info-mode)))

shell

Tramp

(use-package tramp
  :config (add-to-list 'tramp-connection-properties
                       (list nil "session-timeout" nil)))

Shell management

Для удобства запуска новых консолей есть две функции:

  • start-shell(buffer-name &optional cmd) Например: (start-shell “shell_nova” “cd ~/m/nova && vact”)
  • start-ssh (buffer-name host &optional cmd) Подключается к хосту, используя tramp, затем запускает shell. Для подключения к хосту можно использовать tramp, например: (start-ssh “shell_ctl” “fuel|sudo:fuel|ssh:ctl01”)

Часто используемые shell добавляются в shell-alist и вызываются через helm (c-; b).

(defun read-shells-config (fname)
  (read (format "(%s)"
                (with-temp-buffer
                  (insert-file-contents fname)
                  (buffer-string)))))

(defun make-comint-directory-tracking-work-remotely ()
  "Add this to comint-mode-hook to make directory tracking work
    while sshed into a remote host, e.g. for remote shell buffers
    started in tramp. (This is a bug fix backported from Emacs 24:
    http://comments.gmane.org/gmane.emacs.bugs/39082"
  (set (make-local-variable 'comint-file-name-prefix)
       (or (file-remote-p default-directory) "")))

(add-hook 'comint-mode-hook 'make-comint-directory-tracking-work-remotely)

(defun shell-cd (cmd)
  (when (string-match "cd \\([^\n]+\\)" cmd)
    (cd (match-string 1 cmd))))

(defun start-local (buffer-name &optional cmd)
  (shell buffer-name)
  (when cmd
      (shell-cd cmd)
      (with-current-buffer buffer-name
        (shell-procfs-dirtrack-mode))
      (comint-send-string buffer-name (concat cmd "\n"))))

(defun start-ssh (buffer-name host &optional cmd)
  (message (format "starting ssh %s" host))
  (measure-time
   "start-ssh"
   (let ((default-directory (format "/ssh:%s:" host)))
     (shell buffer-name))
   (if cmd
       (comint-send-string buffer-name (concat cmd "\n")))))

(defun start-shell-buffer (buffer host cmd)
  (if host
      (start-ssh bf host cmd)
    (start-local bf cmd)))

(setq shelm-history nil)

(defun run-or-get-shell (name)
  (interactive
   (progn
     (setq shell-alist (read-shells-config "~/.emacs.d/shm/shells.el"))
     (let ((name (helm-comp-read
                  "Select shell: "
                  (mapcar (lambda (item) (list (nth 0 item) (nth 0 item))) shell-alist)
                  :history 'shelm-history)))
       (if (listp name) name (list name)))))
  (let* ((opts (cadr (assoc name shell-alist)))
         (host (plist-get opts 'host))
         (cmd (or (plist-get opts 'cmd) "true"))
         (bf (concat "shell-" name)))
    (message "%s is choosen, host: %s" name host)
    (and
     (get-buffer bf)
     (not (get-buffer-process bf))
     (kill-buffer bf))
    (if (get-buffer bf)
        (switch-to-buffer bf)
      (save-excursion
        (set-buffer "*scratch*")
        (start-shell-buffer bf host cmd)))))

(global-set-key (kbd "C-; x") 'run-or-get-shell)

(load "~/files/prog/shm/shm.el")

Run current file

Запуск текущего файла в compilation mode.

(global-set-key (kbd "<f7>") 'run-current-file)

(defun run-current-file ()
      "Execute or compile the current file.
   For example, if the current buffer is the file x.pl,
   then it'll call “perl x.pl” in a shell.
   The file can be php, perl, python, ruby, javascript, bash, ocaml, java.
   File suffix is used to determine what program to run."
      (interactive)
      (let (extention-alist fname suffix progName cmdStr)
        (setq extention-alist ; a keyed list of file suffix to comand-line program to run
              '(
                ("php" . "php")
                ("pl" . "perl")
                ("py" . "~/.ve/mc/bin/python3")
                ("rb" . "ruby")
                ("js" . "js")
                ("sh" . "bash")
                ("" . "bash")
                ("ml" . "ocaml")
                ("vbs" . "cscript")
                ("java" . "javac")
                ("go" . "go run")
                )
              )
        (setq fname (buffer-file-name))
        (setq suffix (file-name-extension fname))
        (setq progName (cdr (assoc suffix extention-alist)))
        (setq cmdStr (concat progName " \"" fname "\""))

        (if (string-equal suffix "el")
            (load-file fname)
          (if progName                  ; is not nil
              (progn
                (message "Running...")
                (compile (read-shell-command "Command: " cmdStr)))
            ;;(shell-command cmdStr))
            (message "No recognized program file suffix for this file.")
            ))))

Run tmp command

(defun tmp-command()
  (interactive)
  (comint-send-string "shell_placement" "~/m/python-openstackclient/.tox/py27/bin/pytest -vxlk TestSetInventory\n"))
(global-set-key (kbd "<f8>") 'tmp-command)

Eshell

;; for GNU Emacs 26.3
(defun eshell-mode-custom-keys ()
  (local-set-key (kbd "<f9>") 'helm-eshell-history)
  (local-set-key (kbd "M-r") 'helm-eshell-history))
(add-hook 'eshell-mode-hook 'eshell-mode-custom-keys)
;; for GNU Emacs 28.0.50
(require 'em-hist)

(setq helm-show-completion-display-function #'helm-show-completion-default-display-function)
;; (define-key eshell-hist-mode-map (kbd "M-r") 'helm-eshell-history)

orgmode

Установка orgmode и его расширений.

(use-package org)

(use-package org-contrib)

Устанавливаем org-plus-contrib, нужно обновлять в чистом emacs или удалять файлы elc при ошибках компиляции.

Файлы с задачами.

(setq my-org-dir (with-home-dir "org/"))
(setq org-agenda-files
      (mapcar
       #'(lambda (name) (concat my-org-dir name))
       '("task.org" "org-linkz/Linkz.org" "reference.org" "work-gcal.org" "book.org" "film.org" "att-log.org")))

Refile targets where items from any list can be moved. Most recent items should appear on top. It’s more natural way to see recent items first. The same setup as in mail. Done issues go to the bottom of the list. Can view it if needed.

(defun refile-org-files ()
  (let ((files '("task.org" "reference.org" "book.org" "film.org")))
    (mapcar #'(lambda (x) (concat my-org-dir x)) files)))

(setq org-refile-targets '((refile-org-files . (:level . 2)))
      org-reverse-note-order t)

Сочетание, для открытия агенды.

(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c i") 'org-store-link)

Mobile and web accessibility are resolved by https://org-web.org/. All org files are synchronized to Dropbox w/o org-mobile.

org-mode latex

sudo apt-get install texlive-full

C-c C-x C-l runs the command org-preview-latex-fragment (need imagemagick) C-c C-c on fomula - reset image C-c C-x \ runs the command org-toggle-pretty-entities (display unicode values)

Increase font size for latex fragment preview.

(setq org-format-latex-options (plist-put org-format-latex-options :scale 1.6))

See ~/org/pdf-export.org

(add-to-list
 'org-latex-classes
 '("nice-pdf-26" "\\documentclass[14pt,a4paper,hidelinks]{scrartcl}
\\usepackage[T1]{fontenc}
\\usepackage{fontspec}
\\usepackage{graphicx}
\\usepackage{hyperref}
\\usepackage{geometry}
\\usepackage{libertine}

\\geometry{a4paper, textwidth=6.5in, textheight=10in,
            marginparsep=7pt, marginparwidth=.6in}
\\pagestyle{empty}
\\title{}

         [NO-DEFAULT-PACKAGES]
         [PACKAGES]
         [EXTRA]
\\setcounter{secnumdepth}{0}
"
   ("\\subsection{%s}" . "\\subsection*{%s}")
   ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
   ("\\paragraph{%s}" . "\\paragraph*{%s}")
   ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))

(setq org-latex-pdf-process
      '("xelatex -interaction nonstopmode %f"
        "xelatex -interaction nonstopmode %f"))

http://emacs-fu.blogspot.com/2011/04/nice-looking-pdfs-with-org-mode-and.html

Захват сообщений

Шаблоны.

%? - пользовательский ввод. %U - дата. %a - указатель на файл, в котором находишься при захвате. %i - активный регион.

(setq my-task-file (concat my-org-dir "task.org"))
(setq my-bookmark-file (concat my-org-dir "bookmark.org"))
(setq org-capture-templates
      '(("i"
         "Inbox"
         entry
         (file+olp my-task-file "task" "inbox")
         "* TODO %?\n\nAdded: %U\n  %i\n")
        ("f"
         "Inbox with file link"
         entry
         (file+olp my-task-file "task" "inbox")
         "* TODO %?\n\nAdded: %U\n  %i\n%\n")
        ("b"
         "Bookmark"
         entry
         (file+olp my-bookmark-file "Bookmarks" "inbox")
         "* TODO %c %?\n\nAdded: %U\n  %i\n")
        ("m"
         "memorize"
         entry
         (file+olp "~/org/cards/english.org" "words")
         "* %i\t\t:drill:\n    Added: %U\n\n** answer\n\n%?\n")
        ("o" "Link capture" entry
         (file+headline "~/org/org-linkz/Linkz.org" "Catalog")
         "* TODO %a %U\n"
         :immediate-finish t)))

(global-set-key (kbd "C-c c") 'org-capture)

babel

Добавляем языки.

(org-babel-do-load-languages
 'org-babel-load-languages
 '((lisp . t)
   (plantuml . t)
   (shell . t)
   (lisp . t)
   (ditaa . t)
   (R . t)
   (python . t)
   (ruby . t)
   (sql . t)
   (dot . t)
   (C . t)
   (sqlite . t)
   (gnuplot . t)))

Отключаем запрос на подтверждение выполнения.

(setq org-confirm-babel-evaluate nil)

Задаем приложение для обработки.

(setq org-plantuml-jar-path
      (expand-file-name "~/bin/plantuml.jar"))
(setq org-ditaa-jar-path
      (expand-file-name "~/.emacs.d/bin/ditaa0_9.jar"))
(setq org-babel-python-command "PYTHONPATH=$PYTHONPATH:~/files/prog python")
(setq org-babel-sh-command "bash")

Для заголовков можно указывать параметры через property или elisp.

Например: \#+PROPERTY: header-args :session my_python_session \#+PROPERTY: header-args+ :results silent \#+PROPERTY: header-args+ :tangle yes или

(setq org-babel-default-header-args:sh
      (cons '(:results . "scalar replace")
            (assq-delete-all :results org-babel-default-header-args)))

Время

(defun bh/is-project-p-with-open-subtasks ()
  "Any task with a todo keyword subtask"
  (let ((has-subtask)
        (subtree-end (save-excursion (org-end-of-subtree t))))
    (save-excursion
      (forward-line 1)
      (while (and (not has-subtask)
                  (< (point) subtree-end)
                  (re-search-forward "^\*+ " subtree-end t))
        (when (and
               (member (org-get-todo-state) org-todo-keywords-1)
               (not (member (org-get-todo-state) org-done-keywords)))
          (setq has-subtask t))))
    has-subtask))

(defun bh/clock-in-to-started (kw)
  "Switch task from TODO or NEXT to STARTED when clocking in.
Skips capture tasks and tasks with subtasks"
  (if (and (member (org-get-todo-state) (list "TODO" "NEXT"))
           (not (and (boundp 'org-capture-mode) org-capture-mode))
           (not (bh/is-project-p-with-open-subtasks)))
      "STARTED"))

;; добавляет время закрытия таска
(setq org-log-done t)
;; Сохраняем историю подсчета времени между сессиями
(setq org-clock-persist 'history)
(org-clock-persistence-insinuate)
;; Save clock data in the CLOCK drawer and state changes and notes in the LOGBOOK drawer
(setq org-clock-into-drawer "CLOCK")
;; Yes it's long... but more is better ;)
(setq org-clock-history-length 28)
;; Resume clocking task on clock-in if the clock is open
(setq org-clock-in-resume t)
;; Change task state to NEXT when clocking in
(setq org-clock-in-switch-to-state (quote bh/clock-in-to-started))
;; Separate drawers for clocking and logs
(setq org-drawers (quote ("PROPERTIES" "LOGBOOK" "CLOCK")))
;; Sometimes I change tasks I'm clocking quickly - this removes clocked tasks with 0:00 duration
(setq org-clock-out-remove-zero-time-clocks t)
;; Clock out when moving task to a done state
(setq org-clock-out-when-done t)
;; Save the running clock and all clock history when exiting Emacs, load it on startup
(setq org-clock-persist (quote history))
;; Enable auto clock resolution for finding open clocks
(setq org-clock-auto-clock-resolution (quote when-no-clock-is-running))
;; Include current clocking task in clock reports
(setq org-clock-report-include-clocking-task t)
(setq org-deadline-warning-days 1)

(setq org-clock-mode-line-total 'current)

Отображение clock-table в часах.

(setq org-time-clocksum-format
      '(:hours "%d"
        :require-hours t
        :minutes ":%02d"
        :require-minutes t))

Экспорт

(setq org-export-babel-evaluate nil)

Agenda

;; (setq org-agenda-custom-commands
;;       '(("x" agenda)
;;         ("y" agenda*)
;;         ("w" todo "WAITING")
;;         ("W" todo-tree "WAITING")
;;         ("u" tags "+boss-urgent")
;;         ("v" tags-todo "+boss-urgent")
;;         ("U" tags-tree "+boss-urgent")
;;         ("f" occur-tree "\\<FIXME\\>")
;;         ("h" . "HOME+Name tags searches") ; description for "h" prefix
;;         ("hl" tags "+home+Lisa")
;;         ("hp" tags "+home+Peter")
;;         ("hk" tags "+home+Kim")))
(setq org-agenda-custom-commands
      '(("tb" tags-todo "+BOOK")
        ("tr" tags-todo "+READ")
        ("tt" tags-todo "+TASK")
        ("tp" tags-todo "+PROJECT")
        ("tf" tags-todo "+FILM")))

Настройки блоков

(setq org-src-fontify-natively t
      org-src-window-setup 'current-window
      org-src-strip-leading-and-trailing-blank-lines t
      org-src-preserve-indentation t
      org-src-tab-acts-natively t
      org-adapt-indentation nil)

github

(defun org-remove-results-tag ()
  (interactive)
  (save-excursion
    (beginning-of-buffer)
    (let ((cnt 0))
      (while (search-forward "#+RESULTS:" nil t)
        (org-beginning-of-line)
        (org-kill-line)
        (org-kill-line)
        (incf cnt))
      (message "#+RESULTS: lines removed: %d" cnt))))

(defun org-convert-tables ()
  (interactive)
  (save-excursion
    (beginning-of-buffer)
    (let ((cnt 0))
      (while (search-forward "+---" nil t)
        (org-beginning-of-line)
        (org-table-convert)
        (incf cnt))
      (message "%d tables converted" cnt))))

(defun org-prepare-github ()
  (interactive)
  (org-remove-results-tag)
  (org-convert-tables))

Редактирование

(use-package flyspell
  :if (not not-linux)
  :hook
    ((org-mode . flyspell-mode)
     (text-mode . flyspell-mode))
  :config
    (define-key flyspell-mode-map (kbd "C-;") nil))

org-drill

anki

(use-package org-drill
  :if nil
  :ensure t)

org-bookmarks

(use-package org-protocol
  :init (setq org-html-validation-link nil
              org-protocol-default-template-key "o"))

(defun export-linkz-after-saved-file ()
  (if (string-match "Linkz.org" (buffer-file-name))
      (org-html-export-to-html)))

(add-hook 'after-save-hook 'export-linkz-after-saved-file)

Alternative via local vars

Python

Просмотр документации

Для поиска документации по используется pylookup, который индексирует документацию python, и сохраняет индекс локально.

;; add pylookup to your loadpath, ex) "~/.lisp/addons/pylookup"
(setq pylookup-dir (with-emacs-dir "plugins/pylookup"))
(add-to-list 'load-path pylookup-dir)
;; load pylookup when compile time
(eval-when-compile (require 'pylookup))

;; set executable file ande db file
(setq pylookup-program (concat pylookup-dir "/pylookup.py"))
(setq pylookup-db-file (concat pylookup-dir "/pylookup.db"))

;; to speedup, just load it on demand
(autoload 'pylookup-lookup "pylookup"
  "Lookup SEARCH-TERM in the Python HTML indexes." t)
(autoload 'pylookup-update "pylookup"
  "Run pylookup-update and create the database at `pylookup-db-file'." t)

Просмотр документации: pylookup-lookup ищет слово под курсором и предлагает выбор.

(defun pylookup-view-doc-index ()
  (interactive)
  (browse-url (concat "file://"
                      pylookup-dir
                      "/python-2.7.7-docs-html/index.html")))

Tools

(setq pylint-cmd
    (concat "pylint --rcfile ~/files/settings/linters/pylintrc"
            " -rn --msg-template='{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}' "))

(defvar pep257-hist nil)

(defun pep257 ()
  (interactive)
  (let* ((cmd (read-shell-command
               "Command: "
               (concat "~/bin/pep257.py " (file-name-nondirectory (or (buffer-file-name) "")))
               'pep257-hist))
         (null-device nil))
    (grep cmd)))

(setq
 python-shell-interpreter "ipython"
 python-shell-interpreter-args "-i")

Hooks

(defun python-keys ()
  (local-unset-key (kbd "C-c C-d"))
  (local-unset-key (kbd "C-; s"))
  (local-set-key (kbd "C-c C-d h") 'pylookup-lookup)
  (local-set-key (kbd "C-c C-d i") 'pylookup-view-doc-index)
  (local-set-key (kbd "C-c v") 'pep8)
  (local-set-key (kbd "C-c l") 'pylint)
  (local-set-key (kbd "C-c d") 'pep257)
  (local-set-key (kbd "C-; s s") 'occur-python-structure)
  (local-set-key (kbd "C-; s c") 'grep-at-point)
  (local-set-key (kbd "C-; s w") 'what-function-full))

(add-hook 'python-mode-hook 'python-keys)

(add-hook 'python-mode-hook 'which-function-mode)

Запуск тестов

(defun colorize-test-message (message)
  )

(defun run-test-quick (arg)
  (interactive "P")
  (let ((cmd '(concat "~/prog/ttr/bin/ttr " (what-function '(4)))))
    (if (eq (car arg) 4)
        (compile (eval cmd))
      (message
       (shell-command-to-string (eval cmd))))))

(defun multiple-replace (replaces string)
  (if (null replaces)
      string
    (let ((replace (first replaces)))
     (multiple-replace
      (rest replaces)
      (replace-regexp-in-string (first replace) (second replace) string)))))

(defun python-path (file-name function-name)
  (concat (multiple-replace
           `((,(concat (chomp (shell-command-to-string "git rev-parse --show-toplevel")) "/") "")
             ("/" "\.")
             ("\.py$" ""))
             file-name) "." function-name))

(defun what-function (arg)
  (interactive "P")
  (let* ((orig-func (which-function))
         (func (if (eq (car arg) 4)
                  (python-path (buffer-file-name) orig-func)
                 (if (string-match "\\." orig-func)
                     (cadr (split-string orig-func "\\."))
                   orig-func))))
   (kill-new func)
   (message "Copied function name '%s' to the clipboard." func)
   func))

(defun what-function-full ()
  (interactive)
  (what-function '(4)))

(defun add-run-test-quick-key ()
  (local-set-key (kbd "C-c C-t C-t") 'run-test-quick))

(add-hook 'python-mode-hook 'add-run-test-quick-key)

virtualenv

Для удобства работы используется virtualevwrapper for emacs, порт virtualevwrapper.sh, делает все то же но внутри emacs. Команды run-python, shell-command, org-evaluate выполняются с учетом текущей virtualenv

(require 'virtualenvwrapper)
(venv-initialize-interactive-shells) ;; if you want interactive shell support
(venv-initialize-eshell) ;; if you want eshell support
(setq venv-location "~/m/nova/.tox/")

Lisp

(setq inferior-lisp-program "sbcl --dynamic-space-size 2048")
(setq slime-net-coding-system 'utf-8-unix)
(setq slime-contribs '(slime-fancy))

Включаем paredit для мест, где вводится lisp.

(add-hook 'clojure-mode-hook #'enable-paredit-mode)
(add-hook 'cider-mode-hook #'enable-paredit-mode)
(add-hook 'emacs-lisp-mode-hook #'enable-paredit-mode)
(add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode)
;; (add-hook 'ielm-mode-hook #'enable-paredit-mode)
;; (makunbound 'ielm-mode-hook)

(add-hook 'lisp-mode-hook #'enable-paredit-mode)
(add-hook 'lisp-interaction-mode-hook #'enable-paredit-mode)
(add-hook 'scheme-mode-hook #'enable-paredit-mode)
(add-hook 'slime-repl-mode-hook (lambda () (paredit-mode +1)))
;; SLIME’s REPL has the very annoying habit of grabbing DEL
;; which interferes with paredit’s normal operation.
;; To alleviate this problem use the following code:

;; Stop SLIME's REPL from grabbing DEL,
;; which is annoying when backspacing over a '('
(defun override-slime-repl-bindings-with-paredit ()
  (define-key slime-repl-mode-map
    (read-kbd-macro paredit-backward-delete-key) nil))
(add-hook 'slime-repl-mode-hook 'override-slime-repl-bindings-with-paredit)

;; (checkdoc) ;; (package-buffer-info) ;; (byte-compile-file “~/.emacs.d/init.el”) ;; (elint-file “~/.emacs.d/init.el”)

Lisp basic keys

mark-defun - C-M-h prog-indent-sexp - C-M-q paredit-open-<x> - with C-u 1 wraps next sexp (M-( is also available for “(“). Wrap can be done with visual mark. paredit-raise-sexp - M-r paredit-splice-sexp-killing-backward - M-up paredit-forward-slurp-sexp - C-right paredit-forward-barf-sexp - C-left

https://github.com/Fuco1/.emacs.d/blob/master/files/smartparens.el https://ebzzry.io/en/emacs-pairs/#manipulation

JS

Для просмотра json нужна возможность свертывать отдельные блоки, есть hs-minor-mode, который позволяет свертывать только {} блоки.

Настраиваем, чтобы можно было свертывать [].

(add-to-list 'hs-special-modes-alist '(js-mode . ("[{[]" "[}\\]]" "/[*/]" nil)))

Включаем hs-minor-mode для JS.

(defun add-hs-minor-mode()
  (hs-minor-mode))

(add-hook 'js-mode-hook 'add-hs-minor-mode)

(setq js-indent-level 4)

Golang

(defun occur-go-structure ()
  (interactive)
  (occur "func \\|type \\|interface "))


(use-package go-mode
  :ensure t)


(use-package company
  :ensure t)


(use-package lsp-mode
  :ensure t
  )

(add-hook 'go-mode-hook (lambda ()
    (local-set-key (kbd "C-; s s") 'occur-go-structure)
    (local-set-key (kbd "C-; s c") 'grep-at-point)
    (local-set-key (kbd "C-; s f") 'grep-function-at-point)
    (local-set-key (kbd "C-; s w") 'what-function-full)
    (setq tab-width 4)
    (flycheck-mode 1)
    (lsp)
    (add-hook 'before-save-hook 'gofmt-before-save nil 'local)
    (lambda ()
      (push '("error" . ?∇) prettify-symbols-alist)
      (push '("err" . ?⊙) prettify-symbols-alist)
      (push '("exists" . ?∃) prettify-symbols-alist)
      (push '(":= range" . ?∈) prettify-symbols-alist)
      (push '("ok" . ?✓) prettify-symbols-alist)
      (push '("==" . ?≡) prettify-symbols-alist)
      (push '(":=" . ?≔) prettify-symbols-alist)
      (push '(">=" . ?≥) prettify-symbols-alist)
      (push '("<=" . ?≤) prettify-symbols-alist)
      (push '("<-" . ?←) prettify-symbols-alist)
      (push '("!=" . ?≠) prettify-symbols-alist)
      (push '("..." . ?…) prettify-symbols-alist)
      (push '("nil" . ?∅) prettify-symbols-alist)
      (push '("make" . ?&) prettify-symbols-alist)
      (push '("new" . ?&) prettify-symbols-alist)
      (push '("context.Context" . ?◇) prettify-symbols-alist)
      (push '("ctx" . ?⋄) prettify-symbols-alist)
      (push '("mu" . ?❢) prettify-symbols-alist)
      (push '("&&" . ?∧) prettify-symbols-alist)
      (push '("||" . ?∨) prettify-symbols-alist)
      (push '("!" . ) prettify-symbols-alist)
      (push '("interface{}" . ?⋆) prettify-symbols-alist)
      (push '("struct{}" . ) prettify-symbols-alist)
      )
    ))

(global-prettify-symbols-mode +1)

Calendar

(require 'calendar)
(setq calendar-week-start-day 1)
(setq calendar-holidays '((holiday-fixed 11 4 "")
                          (holiday-fixed 1 1 "")
                          (holiday-fixed 1 2 "")
                          (holiday-fixed 1 5 "")
                          (holiday-fixed 1 6 "")
                          (holiday-fixed 1 7 "")
                          (holiday-fixed 1 8 "")
                          (holiday-fixed 1 9 "")
                          (holiday-fixed 2 23 "")
                          (holiday-fixed 3 9 "")
                          (holiday-fixed 5 1 "")
                          (holiday-fixed 5 4 "")
                          (holiday-fixed 5 11 "")
                          (holiday-fixed 6 12 "")))

(defvar iy/calendar-copy-date-format-history '("%Y-%m-%d"))

(defun iy/calendar-copy-date (arg)
  "Copy date under the cursor      . Read format from minibuffer if ARG,
      use recently used format if no ARG . See the function `format-time-string'
      for the document of time format string"
  (interactive "P")
  (let ((date (calendar-cursor-to-date t))
        (format (if arg
                    (completing-read
                     "Date Format:"
                     iy/calendar-copy-date-format-history nil nil nil
                     'iy/calendar-copy-date-format-history nil nil)
                  (car iy/calendar-copy-date-format-history)))
        string)
    (setq date (encode-time 0 0 0 (cadr date) (car date) (nth 2 date)))
    (setq string (format-time-string format date))
    (if (eq last-command 'kill-region)
        (kill-append string nil)
      (kill-new string))))

(define-key calendar-mode-map "c" 'iy/calendar-copy-date)
(defun yesterday-time ()
  "Provide the date/time 24 hours before the time now in the format of current-time."
  (setq
   now-time (current-time)              ; get the time now
   hi (car now-time)                    ; save off the high word
   lo (car (cdr now-time))              ; save off the low word
   msecs (nth 2 now-time)               ; save off the milliseconds
   )

  (if (< lo 20864)                      ; if the low word is too small for subtracting
      (setq hi (- hi 2)  lo (+ lo 44672)) ; take 2 from the high word and add to the low
    (setq hi (- hi 1) lo (- lo 20864))  ; else, add 86400 seconds (in two parts)
    )
  (list hi lo msecs)                    ; regurgitate the new values
  )

Yaml

(use-package yaml-mode
  :init

  (defun copy-visible-only ()
    (interactive)
    (cl-flet ((buffer-substring 'buffer-substring-selective-display-only))
      (if (use-region-p)
          (progn
            (kill-new (buffer-substring (region-beginning) (region-end)))
            (message "Text selection copied."))
        (progn
          (kill-new (buffer-substring (point-min) (point-max)))
          (message "Buffer content copied.")))))

  (defun buffer-substring-selective-display-only (start end)
    (when (> start end) (setq start (prog1 end (setq end start))))
    (let* ((filter-buffer-substring-function
            (lambda (beg end _delete)
              (let* ((strg (buffer-substring beg end)))
                (if selective-display
                    (let ((regexp (format "^[[:space:]]\\{%s,\\}" selective-display)))
                      (message "Selective display enabled, flushing lines with regexp: %s" regexp)
                      (setq strg (with-temp-buffer
                                   (insert strg)
                                   (goto-char (point-min))
                                   (flush-lines regexp)
                                   (buffer-string)))))

                (set-text-properties 0 (length strg) () strg)
                strg))))
      (filter-buffer-substring start end)))

  (defun aj-toggle-fold ()
    "Toggle fold all lines larger than indentation on current line"
    (interactive)
    (let ((col 1))
      (save-excursion
        (back-to-indentation)
        (setq col (+ 1 (current-column)))
        (set-selective-display
         (if selective-display nil (or col 1))))))
  :bind
  (:map yaml-mode-map
        ("C-c t" . aj-toggle-fold)))

(use-package highlight-indent-guides
  :hook
  ((yaml-mode . highlight-indent-guides-mode)))

Experiments

(autoload 'bash-completion-dynamic-complete
  "bash-completion"
  "BASH completion hook")
(add-hook 'shell-dynamic-complete-functions
  'bash-completion-dynamic-complete)

run nova repl

(prefer-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)

(defun display-ansi-colors ()
  (interactive)
  (let ((inhibit-read-only t))
    (ansi-color-apply-on-region (point-min) (point-max))))

(require 'ansi-color)
(defun colorize-compilation-buffer ()
  (let ((inhibit-read-only t))
    (ansi-color-apply-on-region (point-min) (point-max))))
(add-hook 'compilation-filter-hook 'colorize-compilation-buffer)

(use-package bash-completion
  :ensure t)

(setq js-indent-level 2)

(use-package markdown-toc
  :ensure t)

(use-package string-inflection
  :ensure t)

(fset 'mm-json-to-grpc
   (kmacro-lambda-form [tab escape ?  backspace tab ?s ?t ?r ?i ?n ?g ?  ?\C-d ?\C-s ?: backspace ?\" return backspace ?\C-k ?  ?= ?  ?\M-x ?m ?a ?c ?r ?o ?- ?i ?n backspace backspace backspace backspace backspace backspace backspace backspace ?k ?m ?a ?c ?r ?o ?- ?i ?n ?s ?e ?r ?t ?- ?c ?o ?u ?n ?t ?e ?r return ?\; ?\C-n ?\C-a] 11 "%d"))

(fset 'mm-add-json-name
   (kmacro-lambda-form [?\C-s ?  ?\C-s ?\C-s ?\C-s ?\C-s return ?\C-  ?\C-s ?  return ?\C-b ?\M-w ?\C-e ?\C-b ?  ?\[ ?j ?s ?o ?n ?_ ?n ?a ?m ?e ?  ?= ?  ?\" ?\C-y ?\" ?\] ?\C-n ?\C-a] 0 "%d"))

(fset 'mm-upcase
   (kmacro-lambda-form [?\C-s ?_ return backspace ?\M-x ?u ?p ?c ?a ?s ?e ?- ?c ?h ?a ?r return ?\C-n ?\C-a] 0 "%d"))

(fset 'mm-json-to-golang
   (kmacro-lambda-form [tab ?\C-d ?\C-d ?\C-d ?\C-d ?\C-d ?\C-d ?\C-d ?\C-d ?\C-f ?\M-r ?\M-x ?s ?t ?r ?i ?n ?g ?- ?i ?f ?l ?e ?c ?t ?i ?o ?n ?- ?l ?o backspace backspace ?c ?a backspace backspace backspace backspace backspace backspace backspace backspace backspace backspace backspace ?n ?f ?l ?e ?c ?t ?i ?o ?n ?- ?c ?a ?m ?e return ?\C-n ?\C-a] 0 "%d"))

(fset 'mm-json-to-grpc2
   (kmacro-lambda-form [?  ?  ?  ?  ?\C-d ?s ?t ?r ?i ?n ?g ?  ?\C-s ?\" return backspace ?\C-  ?\C-r ?  ?\C-f ?\M-w ?\M-x ?s ?t ?r ?i ?n ?g ?- ?i ?n ?f ?l ?e ?c ?t ?i ?o ?n ?- ?c ?a ?m ?e ?l ?c ?a ?s ?e return ?  ?= ?  ?\M-x ?k ?m ?a ?c ?r ?o ?- ?i ?n ?s return ?  ?\[ ?j ?s ?o ?n ?_ ?n ?a ?m ?e ?  ?= ?  ?\" ?\C-y ?\" ?\C-k ?\] ?s backspace ?\; ?\C-n ?\C-a] 26 "%d"))

(push
 (cons
  "docker"
  '((tramp-login-program "sudo docker")
    (tramp-login-args (("exec" "-it") ("%h") ("/bin/bash")))
    (tramp-remote-shell "/bin/sh")
    (tramp-remote-shell-args ("-i") ("-c"))))
 tramp-methods)

(defadvice tramp-completion-handle-file-name-all-completions
  (around dotemacs-completion-docker activate)
  "(tramp-completion-handle-file-name-all-completions \"\" \"/docker:\" returns
    a list of active Docker container names, followed by colons."
  (if (equal (ad-get-arg 1) "/docker:")
      (let* ((dockernames-raw (shell-command-to-string "sudo docker ps | perl -we 'use strict; $_ = <>; m/^(.*)NAMES/ or die; my $offset = length($1); while(<>) {substr($_, 0, $offset, q()); chomp; for(split m/\\W+/) {print qq($_:\n)} }'"))
             (dockernames (cl-remove-if-not
                           #'(lambda (dockerline) (string-match ":$" dockerline))
                           (split-string dockernames-raw "\n"))))
        (setq ad-return-value dockernames))
    ad-do-it))

(defun my-term-mode-hook ()
  (define-key term-raw-map (kbd "C-y") 'term-paste)
  (define-key term-raw-map (kbd "C-k")
    (lambda ()
      (interactive)
      (term-send-raw-string "\C-k")
      (kill-line))))
(add-hook 'term-mode-hook 'my-term-mode-hook)


(defun snippet (start end)
  (interactive
   (if mark-active
       (list (region-beginning) (region-end))
     (list (point-min) (point-max))))
  (let ((selection (buffer-substring-no-properties start end)))
    (message "posting...")
    (write-region selection
              nil "/tmp/snippet"
              nil 'quiet)
    (let ((r (shell-command-to-string (format "cat /tmp/snippet | snippet.py" selection))))
      (message r)
      (kill-new r))))

(use-package lsp-docker)

(defun eldoc-documentation-default())

Автозапуск

(measure-time "emacs.org"
 (find-file "~/emacs-conf/emacs.org"))
(find-file "~/org/task.org")
(measure-time "db.gpg"
 (find-file "~/files/cpp/db.gpg"))
(find-file (format-time-string comint-history-file (current-time)))
(find-file "~/org/reference.org")
(find-file "~/.emacs.d/shm/shells.el")
(find-file "~/org/log.org")
(end-of-buffer)
(switch-to-buffer-other-window "task.org")
(ace-window 0)
(server-start)

Links

ML archive http://lists.gnu.org/archive/html/emacs-devel/

Emacs commits http://git.savannah.gnu.org/cgit/emacs.git/log/

Git repo git://git.savannah.gnu.org/emacs.git

About

My emacs configuration

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published