Skip to content

Latest commit

 

History

History
1308 lines (1152 loc) · 42.3 KB

archive.org

File metadata and controls

1308 lines (1152 loc) · 42.3 KB

celestial-mode-line

Update theme with sun.

(use-package celestial-mode-line
  :config
  (require 'kimim)
  (defun kimim/update-theme-with-sun (orig-fun &optional date)
    (let* ((sunrise-symbol
            (cdr (assoc
                  'sunrise
                  celestial-mode-line-sunrise-sunset-alist)))
           (sunset-symbol
            (cdr (assoc
                  'sunset
                  celestial-mode-line-sunrise-sunset-alist)))
           (sunrise-before
            (string-search sunrise-symbol
                           celestial-mode-line-string))
           (sunset-before
            (string-search sunset-symbol
                           celestial-mode-line-string)))
      (apply orig-fun date)
      (let* ((sunrise-after
              (string-search sunrise-symbol
                             celestial-mode-line-string))
             (sunset-after
              (string-search sunset-symbol
                             celestial-mode-line-string)))
        (cond
         ((and (not sunset-before)
               sunset-after)
          (kimim/theme-light))
         ((and (not sunrise-before)
               sunrise-after)
          (kimim/theme-night))))))

  (advice-add 'celestial-mode-line-update
              :around
              #'kimim/update-theme-with-sun)

  (celestial-mode-line-start-timer))

lsp-mode

lsp mode

lsp-mode aims to provide IDE-like experience.

If you got error: Symbol’s function definition is void: -compose, make sure that dash version higher than 2.18 is installed[fn:11].

(use-package dash
  :ensure t)
(use-package goto-addr
  :config
  ;;(setq goto-address-uri-schemes-ignored '("mailto:" "data:" "jar:"))
  (setq goto-address-uri-schemes
        (cons "C:" (seq-reduce (lambda (accum elt) (delete elt accum))
                        goto-address-uri-schemes-ignored
                        (copy-sequence thing-at-point-uri-schemes))))
  (setq goto-address-url-regexp
        (concat "\\<"
                (regexp-opt goto-address-uri-schemes t)
                thing-at-point-url-path-regexp)))
(use-package treemacs)

lsp-mode will add company-capf in front for company-backends, then it will prevent my global company-backends settings. You can customize lsp-completion-provider to :none prevent this.

(use-package lsp-mode
  :after goto-addr
  :commands lsp
  :custom
  (lsp-headerline-breadcrumb-icons-enable t)
  (lsp-headerline-breadcrumb-enable t)
  (lsp-modeline-code-action-fallback-icon "")
  (lsp-completion-provider :none)
  :bind (:map
         lsp-mode-map
         ("C-x l l" . lsp-ui-doc-glance)
         ("C-." . lsp-find-definition)
         ("C-," . xref-go-back)
         ("C-x ." . kimim/lsp-find-definition-other-window)
         ("C-x l t s" . lsp-treemacs-symbols))
  :hook ((c-mode c++-mode clojure-mode) . lsp)
  :config
  (require 'dash)
  (require 'goto-addr)
  (define-key lsp-mode-map (kbd "C-x l") lsp-command-map)
  (add-hook 'xref-after-return-hook 'recenter)
  (defun kimim/lsp-find-definition-other-window ()
    (interactive)
    (lsp-find-definition :display-action 'window)
    (other-window 1)))

lsp-ui

UI helper for lsp-mode.

(use-package lsp-ui
  :commands lsp-ui-mode
  :custom
  (lsp-ui-doc-text-scale-level -1)
  (lsp-ui-doc-show-with-cursor nil)
  (lsp-ui-doc-show-with-mouse nil)
  (lsp-ui-sideline-show-code-actions t)
  (lsp-ui-doc-alignment 'window)
  (lsp-ui-doc-max-width 90))

lsp-clangd

(use-package lsp-clangd
  :ensure lsp-mode
  :custom (lsp-clients-clangd-args
           '("--header-insertion-decorators=0"
             "--all-scopes-completion"
             "--completion-style=detailed"
             "--background-index"
             "--clang-tidy"
             "--header-insertion=iwyu"
             "--pch-storage=memory"
             "-j=12")))

lsp-clangd cannot find definition before visiting the .c file, so we will use ggtags to locate the definition in .c file. After that, lsp-clangd can index .c files.

Completion

yasnippet

(use-package yasnippet
  :defer 10
  :diminish yas-minor-mode
  :defines warning-suppress-types
  :config
  (require 'warnings)
  (add-to-list
   'yas-snippet-dirs (concat kimim/path-sync-emacs "snippets"))
  (yas-global-mode 1)
  (setq warning-suppress-types '((yasnippet backquote-change))))

In order to remove following warning:

Warning (yasnippet): ‘xxx’ modified buffer in a backquote expression. To hide this warning, add (yasnippet backquote-change) to ‘warning-suppress-types’.

clj-refactor

(use-package clj-refactor
  :config
  (setq clojure-thread-all-but-last t)
  (cljr-add-keybindings-with-prefix "C-c r")
  (define-key clj-refactor-map "\C-ctf" #'clojure-thread-first-all)
  (define-key clj-refactor-map "\C-ctl" #'clojure-thread-last-all)
  (define-key clj-refactor-map "\C-cu" #'clojure-unwind)
  (define-key clj-refactor-map "\C-cU" #'clojure-unwind-all)
  (add-to-list 'cljr-magic-require-namespaces '("s"  . "clojure.string")))

company mode

(use-package company
  :defer 10
  :functions (company-abort)
  :bind
  (("C-x m c" . company-mode)
   :map company-active-map
   ("C-n" . company--select-next-and-warn)
   ("C-p" . company--select-previous-and-warn)
   ("C-h" . delete-backward-char)
   ("C-d" . delete-forward-char)
   ("SPC" . (lambda ()
              (interactive)
              (company-abort)
              (insert-char ?\x20))))
:diminish company-mode
  :commands (global-company-mode)
  :custom
  (company-idle-delay 0)
  (company-minimum-prefix-length 1)
  :config
  (require 'company-posframe)
  (global-company-mode t)
  (setq company-backends
        '((company-yasnippet
           company-keywords
           company-capf
           company-files :separate)
          (company-dabbrev
           company-dabbrev-code
           company-ebdb
           company-ispell :with))))

company dict

complete with keyword and annotation. need special dict files for different mode.

(use-package company-dict
  :config
  ;; Where to look for dictionary files
  (setq company-dict-dir (concat kimim/path-sync-emacs "dict")))

company-shell

(use-package company-shell
  :commands company-shell
  :config
  (add-hook
   'eshell-mode-hook
   (lambda ()
     (make-local-variable company-backends)
     (setq company-backends
           '((company-shell company-files)
             company-capf company-yasnippet
             company-dabbrev company-ebdb company-ispell
             (company-dabbrev-code
              company-gtags
              company-etags company-keywords))))))

company-try-hard

If no candidates satisfies our needs, we can type C-\ to get more candidates from following backends from company-backends.

(use-package company-try-hard
  :bind ("C-\\" . company-try-hard))

company-posframe

This extension won’t clutter the buffer contents.

(use-package company-posframe
  :diminish company-posframe-mode
  :config
  (company-posframe-mode 1))

company-ebdb

(use-package company-ebdb)

company statistics

Sort candidates using completion history.

(use-package company-statistics
  :config
  (company-statistics-mode 1))

Text Mode company

(use-package text-mode
  :ensure nil
  :config
  (add-hook
   'text-mode-hook
   (lambda ()
     (make-local-variable 'company-backends)
     (setq company-backends
           '((company-ispell company-capf
              company-yasnippet company-dabbrev
              company-ebdb company-files :seperate))))))

Orgmode

org-indent

If org-modern-star is not enabled, not workaround is required for org-indent:

(defun org-indent--compute-prefixes ()
  "Compute prefix strings for regular text and headlines."
  (setq org-indent--heading-line-prefixes
        (make-vector org-indent--deepest-level nil))
  (setq org-indent--inlinetask-line-prefixes
        (make-vector org-indent--deepest-level nil))
  (setq org-indent--text-line-prefixes
        (make-vector org-indent--deepest-level nil))
  (dotimes (n org-indent--deepest-level)
    (let ((indentation (if (<= n 1) 0
                         (* (1- org-indent-indentation-per-level)
                            (1- n)))))
      ;; Headlines line prefixes.
      (let ((heading-prefix (make-string indentation ?*)))
        (aset org-indent--heading-line-prefixes
              n
              (org-add-props heading-prefix nil 'face 'org-indent))
        ;; Inline tasks line prefixes
        (aset org-indent--inlinetask-line-prefixes
              n
              (cond ((<= n 1) "")
                    ((bound-and-true-p org-inlinetask-show-first-star)
                     (concat org-indent-inlinetask-first-star
                             (substring heading-prefix 1)))
                    (t (org-add-props heading-prefix nil
                         'face 'org-indent)))))
      ;; Text line prefixes.
      ;; remove one prefix char in indent
      (let ((remove-space (if (> n 0)
                              (- n 1)
                            0)))
        (aset org-indent--text-line-prefixes
              n
              (org-add-props
                  (concat
                   (make-string
                    (- (+ n indentation) remove-space) ?\s)
                   (and (> n 0)
                        (char-to-string org-indent-boundary-char)))
                  nil 'face 'org-indent))))))

org-superstar

(use-package org-superstar
  :ensure t
  :hook
  ((org-mode . org-superstar-mode)
   (org-mode . (lambda ()
                 "Beautify Org Symbols"
                 (push '(":category:" . "") prettify-symbols-alist)
                 (push '("[X]" . "" ) prettify-symbols-alist)
                 (push '("[ ]" . "" ) prettify-symbols-alist)
                 (push '("#+begin_src" . "«" ) prettify-symbols-alist)
                 (push '("#+end_src" . "»" ) prettify-symbols-alist)
                 (prettify-symbols-mode))))
  :custom
  (org-superstar-remove-leading-stars t)
  (org-superstar-headline-bullets-list
   '(?⦿ ?○ ?● ?◌))
  (org-superstar-item-bullet-alist
   '((?* . ?●) (?+ . ?♦) (?- . ?▬))))

Frame

Before an emacsclient first connect to daemon, the daemon is working in terminal mode. Thus (display-graphic-p) will return nil. So I add raise-frame in after-make-frame-functions to force emacs to bring the new frame to the front and apply the gui related settings.

(use-package frame
  :ensure nil
  :defer 1
  :bind ("C-x m w" . make-frame)
  :config
  (add-hook 'after-make-frame-functions
            (lambda (frame)
              (select-frame frame)
              (kimim/menu-and-bar)
              (kimim/frame-and-font)
              (raise-frame frame))))

Edit

swiper replaces isearch

(use-package swiper
  :custom
  (swiper-action-recenter t)
  :bind
  ("C-s" . swiper)
  ("M-s ." . swiper-thing-at-point))

visual-fill-column

[2023-05-18 Thu] Many markdown file contains long lines, visual-fill-column can visually wrap lines. But because I use olivetti-mode for text files, now I don’t use this package anymore.

(use-package visual-fill-column
  :hook (markdown-mode . visual-fill-column-mode))

consult-org-roam

(use-package consult-org-roam
  :ensure t
  :diminish consult-org-roam-mode
  :custom
  (consult-org-roam-grep-func #'consult-ripgrep)
  :bind
  ("C-c n e" . consult-org-roam-file-find)
  ("C-c n l" . consult-org-roam-backlinks)
  ("C-c n s" . consult-org-roam-search)
  :config
  (require 'consult-org-roam)
  ;; Activate the minor-mode
  (consult-org-roam-mode 1)
  ;; Eventually suppress previewing for certain functions
  (consult-customize
   consult-org-roam-forward-links
   :preview-key "M-.")
  (consult-customize
   org-roam-node-find
   :preview-key "M-."))

ag: the silver searcher

ag [fn:9] is really a very fast grep tool, and ag.el [fn:10] provide the Emacs interface to ag:

(use-package ag
  :bind
  ("C-x g" . ag-project)
  :config
  (setq ag-highlight-search t))

pt: the platium searcher

Because counsel-ag is not working in my Win64 machine, so I switch to pt now.

Download pt from https://github.com/monochromegane/the_platinum_searcher/releases, and it works out of the box.

ivy-mode

(use-package ivy
  :diminish ivy-mode
  :bind ("<f6>" . ivy-resume)
  :config
  (setq ivy-use-virtual-buffers t)
  (setq ivy-count-format "(%d/%d) ")
  (setq ivy-wrap nil)
  (ivy-mode 1))

counsel

counsel will enhance many built-in commands with nice ivy completion candidates.

(use-package counsel
  :bind
  (("M-x" . counsel-M-x)
   ("C-x C-f" . counsel-find-file)
   ("C-x m f" . counsel-describe-function)
   ("C-x m v" . counsel-describe-variable)
   ("C-x m l" . counsel-load-library)
   ("C-x m i" . counsel-info-lookup-symbol)
   ("C-x m j" . counsel-bookmark)
   ("C-x m u" . counsel-unicode-char)
   ("C-c j" . counsel-git-grep)
   ("C-c g" . counsel-grep)
   ("C-x b" . counsel-ibuffer)
   ("C-c k" . counsel-ag)
   ("C-c p" . counsel-pt)
   :map read-expression-map
   ("C-r" . counsel-minibuffer-history))
  :config
  (require 'ivy)
  (require 'smex)
  (add-hook 'counsel-grep-post-action-hook 'recenter))

guru mode

guru-mode warns you when you type arrow keys, home or end. This could help you to establish the habit of efficiently using emacs keybinding.

(use-package guru-mode
  :diminish guru-mode
  :config
  (guru-global-mode +1))

undo-tree

C-x u is undo command, now it is rebind to undo-tree, when it is invoked, emacs will show the undo tree of current buffer. By default, undo-tree file is kept in the same folder, undo-tree-history-directry-alist is used to specify the one directory for all backups.

(use-package undo-tree
  :diminish undo-tree-mode
  :custom
  (undo-tree-visualizer-timestamps t)
  (undo-tree-visualizer-diff t)
  (undo-tree-history-directory-alist '(("." . "~/temp/")))
  :config
  (global-undo-tree-mode))

auto-highlight-symbol

Automatically highlight current symbol where the cursor is inside.

(use-package auto-highlight-symbol
  :diminish auto-highlight-symbol-mode
  :bind ("C-x m e" . ahs-edit-mode)
  :config
  (global-auto-highlight-symbol-mode t))

poly-org

Polymode [fn:21] is a framework for multiple major modes (MMM) inside a single Emacs buffer. It is comfortable to enable it during literating program.

;;(use-package poly-org
;;  :ensure t)

deft

(use-package deft
  :bind
  ("C-x d" . deft-find-file)
  :custom (deft-text-mode 'org-mode)
  :functions (kimim/deft-open-file-advice
              kimim/deft-new-file-named-advice
              kimim/genfile-timestamp)
  :config
  (use-package ivy)
  (setq deft-extensions '("txt" "org" "md"))
  (setq deft-directory kimim/path-notes)
  (setq deft-recursive t)
  ;; disable auto save
  (setq deft-auto-save-interval 0)
  (setq deft-file-naming-rules '((noslash . "_")))
  (setq deft-use-filter-string-for-filename t)
  (setq deft-org-mode-title-prefix t)
  (setq deft-use-filename-as-title nil)
  (setq deft-strip-summary-regexp
        (concat "\\("
                "[\n\t]" ;; blank
                "\\|^#\\+[[:upper:]_]+:.*$" ;; org-mode metadata
                "\\|^#\\+[[:alnum:]_]+:.*$" ;; org-mode metadata
                "\\)"))

  ;;advise deft-open-file to replace spaces in file names with _
  (require 'kimim)
  (defun kimim/deft-open-file-advice (orig-fun &rest args)
    (let (name title)
      (setq name (pop args))
      (if (file-exists-p name)
          (progn
            (push name args)
            (apply orig-fun args))
        (progn
          (setq title (file-name-sans-extension
                       (file-name-nondirectory name)))
          (setq name (concat
                      (file-name-directory name)
                      (kimim/genfile-timestamp)
                      (downcase
                       (replace-regexp-in-string
                        " " "_" (file-name-nondirectory name)))
                      (if (not (file-name-extension name))
                          ".txt")))
          (push name args)
          (apply orig-fun args)
          (insert (concat "#+TITLE: " title "\n\n"))))))

  (advice-add 'deft-open-file
              :around #'kimim/deft-open-file-advice)

  (defun kimim/deft-new-file-named-advice (orig-fun &rest args)
    (let (name title)
      (setq name (pop args))
      (setq title name)
      (setq name (concat
                  (kimim/genfile-timestamp)
                  (downcase
                   (replace-regexp-in-string
                    " " "_" name))))
      (push name args)
      (apply orig-fun args)
      (insert (concat "#+TITLE: " title "\n\n"))))

  (advice-add 'deft-new-file-named
              :around #'kimim/deft-new-file-named-advice))

org link: match

New link to use everything to locate a file with unique ID:

(use-package org
  :functions org-match-open
  :config
  (org-link-set-parameters "match"
                           :follow #'org-match-open)

  (defun org-match-open (path)
    "Visit the match search on PATH.
     PATH should be a topic that can be thrown at everything/?."
    (w32-shell-execute
     "open" "Everything" (concat "-search " path))))

Install fonts

Because Incosolata font is really great for programming, and Microsoft Yahei is nice font to view Chinese characters, you’d better download and install these fonts from:

For Windows and macOS, you can view and install fonts with font viewer.

For Linux, you could just move all above font files to /usr/local/share/fonts/.

Everything

Everything[fn:14] is a wonderful fast file and folder search engine, it provide a command line tool to get search result from Everything to command line output: es.exe [fn:15].

Reminded that Everything should be running in background to do the real search task for es.exe.

(use-package everything
  :defer t
  :ensure t
  :init
  (setq everything-cmd (concat kimim/path-kimikit "bin/es.exe")))

helm

(use-package helm)

Simplenote2

(use-package markdown-mode
  :defer t
  :ensure t
  )

(use-package simplenote2
  :defer t
  :ensure t
  :bind
  (
   ("C-x p" . simplenote2-list)
   ;; when in Chinese environment, / is a dot, confusing
   ("C-;" . simplenote2-list-filter-notes)
   ("C-." . simplenote2--create-note-locally))
  :config
  (require 'simplenote2)
  (require 'markdown-mode)
  ;;(require 'visual-fill-column)
  (setq simplenote2-notes-mode 'markdown-mode)
  ;;(add-hook 'simplenote2-note-mode-hook 'visual-fill-column-mode)
  (simplenote2-setup)
  )

New orgmode link type for simplenote2. The reason for creating a new kind of link type is that the newly added note is located under folder “new”, while the synchronized notes are in “notes”. We should ensure that all the link points to note in “notes” folder.

(use-package org
  :defer t
  :config
  (org-add-link-type "simplenote2" 'org-simplenote2-open)

  (defun org-simplenote2-open (path)
    (find-file (concat simplenote2-directory "notes/" path)))

  (defun simplenotes-linkto-note ()
    "extract orgmode link string to this note"
    (interactive)
    (unless (buffer-file-name)
      (error "No file for buffer %s" (buffer-name)))
    (beginning-of-buffer)
    (let (title msg)
      ;;fetch first line string as title
      (setq title (buffer-substring-no-properties
                   (line-beginning-position) (line-end-position)))
      ;;package orgmode line with buffer name and title
      (setq msg (format "[[simplenote2:%s][%s]]"
                        (file-name-nondirectory (buffer-file-name))
                        title))
      (kill-new msg)
      (message msg))))

BBDB for contact management

(use-package bbdb
  :defer t
  :bind
  :config
  (setq bbdb-file (concat kimim/path-sync "kimikit/emacs.d/bbdb"))
  ;; https://www.emacswiki.org/emacs/BbdbMailingLists
  ;;(add-hook 'message-setup-hook 'bbdb-mail-aliases)
  )

GNUS setting

;; gnus settings
(use-package gnus
  :ensure nil
  :defer t
  :bind
  (("C-x m m" . kimim/mail-new-empty)
   ("C-x m n" . kimim/mail-new)
   ("C-x m y" . kimim/mail-attach-files)
   :map gnus-summary-mode-map
   ("g" . gnus-summary-insert-new-articles)
   ("f" . gnus-summary-forward-with-original)
   ("R" . gnus-summary-very-wide-reply-with-original)
   ("<delete>" . gnus-summary-delete-article)
   ("<insert>" . mail-archive-kimim))
  :config
  (message "......gnus[0]")
  (use-package ebdb)
  (use-package gnus-dired :ensure nil)
  (setq gnus-visible-headers
        "^Subject:\\|^From:\\|^To:\\|^[BGF]?CC:\\|^Date:")
  (setq gnus-sorted-header-list
        '("^Subject:" "^From:""^To:" "^[BGF]?CC:" "^Date:"))
  (setq compose-mail-user-agent-warnings nil) ;; remove warning
  (setq message-directory "~/Gnus/Mail/")
  (setq gnus-directory "~/Gnus/News/")
  (setq nnfolder-directory "~/Gnus/Mail/Archive")
  ;; unfortunately, following variable not support CN strings
  (setq gnus-permanently-visible-groups "\\(Inbox\\|INBOX\\|已发送邮件\\)")
  (setq mail-self-blind t)
  (setq gnus-alias-override-user-mail-address t)
  (setq mail-signature-file (concat kimim/path-sync "kimikit/emacs.d/signature.txt"))
  (setq gnus-asynchronous t)
  (setq gnus-use-article-prefetch 1000)
  (setq gnus-fetch-old-headers 'some)
  ;; fetch only 50 latest articles to speed up downloading
  (setq gnus-large-newsgroup 50)
  (setq message-forward-as-mime t)
  (setq message-forward-before-signature t) ;; put signature before the fwd msg
  (setq message-forward-included-headers "^Date\\|^From\\|^To\\|^Subject:")
  (setq message-make-forward-subject-function 'message-forward-subject-fwd)
  (setq gnus-user-date-format-alist
        '(((gnus-seconds-today) . "Today %H:%M")
          ((+ 86400 (gnus-seconds-today)) . "Yest. %H:%M")
          (604800 . "%a %H:%M")               ; That's one week
          ((gnus-seconds-month) . "%a %H:%M")
          ((gnus-seconds-year) . "%b %d")
          (t . "%b %d %Y")))
  (setq gnus-summary-line-format
        ":%U%R | %d%13&user-date; %-13,13f (%5k) | %B %s %-120= \n")
  (setq gnus-article-sort-functions '((not gnus-article-sort-by-date)))
  (setq gnus-thread-sort-functions '((not gnus-thread-sort-by-date)))
  (setq gnus-thread-ignore-subject t)
  (setq gnus-agent t)
  (setq gnus-agent-expire-days 90)
  ; prompt for how many articles only for larger than 1000 articles
  (setq gnus-large-newsgroup 100)
  (setq gnus-use-cache t)
  (setq gnus-fetch-old-headers 1) ; show previous messages in a thread
  (setq gnus-thread-indent-level 1)
  (setq gnus-show-threads t)
  (setq gnus-thread-hide-subtree nil)
  (add-hook 'gnus-summary-prepare-hook 'gnus-summary-hide-all-threads)
  ;;(use-package orgalist)
  ;;(add-hook 'message-mode-hook 'orgalist-mode)
  (add-hook 'message-mode-hook 'turn-off-auto-fill)
  (defun gnus-summary-forward-with-original (n &optional wide)
    "Start composing a reply mail to the current message.
The original article will be yanked."
    (interactive "P")
    (gnus-summary-reply (gnus-summary-work-articles n) wide)
    (mail-to)
    (message-beginning-of-line)
    (kill-line)
    (mail-subject)
    (message-beginning-of-line)
    (delete-char 2)
    (narrow-to-region (line-beginning-position) (line-end-position))
    (goto-char (point-min))
    (while (search-forward "Fw: " nil t)
      (replace-match ""))
    (while (search-forward "转发: " nil t)
      (replace-match ""))
    (widen)
    (message-beginning-of-line)
    (insert "FW")
    (mail-to))

  (define-key gnus-summary-mode-map
    [remap gnus-summary-followup-with-original]
    'gnus-summary-forward-with-original)

  (define-key gnus-summary-mode-map
    [remap gnus-summary-reply]
    'gnus-summary-reply-with-original)

  (define-key gnus-summary-mode-map
    [remap gnus-summary-wide-reply]
    'gnus-summary-very-wide-reply-with-original)

  (add-hook 'gnus-message-setup-hook 'kimim/mail-setup))

C

;; Define the modes/packages you need
(use-package company-irony)
(use-package company-c-headers)

(use-package irony
  :diminish irony-mode
  :config
  (setq w32-pipe-read-delay 0)
  (use-package company-irony)
  (add-hook 'irony-mode-hook 'company-irony-setup-begin-commands)
  (add-hook 'irony-mode-hook 'irony-cdb-autosetup-compile-options)
  (require 'flycheck)
  (add-hook 'c-mode-hook 'flycheck-mode)
  (add-hook 'c++-mode-hook 'flycheck-mode)
  (use-package company)
  (use-package company-c-headers)
  (add-to-list 'company-c-headers-path-system "/usr/include")

  ;; replace the `completion-at-point' and `complete-symbol' bindings in
  ;; irony-mode's buffers by irony-mode's function
  (defun my-irony-mode-hook ()
    (define-key irony-mode-map [remap completion-at-point]
      'irony-completion-at-point-async)
    (define-key irony-mode-map [remap complete-symbol]
      'irony-completion-at-point-async))
  (add-hook 'irony-mode-hook 'my-irony-mode-hook))

(use-package company-c-headers)

(use-package flycheck
  :config
  ;; set up flycheck
  (add-hook 'flycheck-mode-hook #'flycheck-irony-setup))

(use-package cc-mode
  :ensure nil
  :config
  (add-to-list 'auto-mode-alist '("\\.C\\w*\\'" . c-mode))
  (use-package company)
  (use-package company-irony)
  (add-to-list 'company-backends 'company-irony)
  (use-package company-c-headers)
  (add-to-list 'company-c-headers-path-system "/usr/include")
  (require 'irony)
  (add-hook 'c-mode-hook 'irony-mode)
  (add-hook 'c++-mode-hook 'irony-mode)
  (add-hook 'objc-mode-hook 'irony-mode)
  (require 'flycheck)
  (add-hook 'c-mode-hook 'flycheck-mode)
  (add-hook 'c++-mode-hook 'flycheck-mode)
  (require 'ggtags)
  (add-hook 'c-mode-hook 'ggtags-mode)
  (add-hook 'c++-mode-hook 'ggtags-mode)

  (add-hook 'c-mode-common-hook
            (lambda ()
              ;; show column width indicator
              ;;(fci-mode 0)
              ;;(syntax-subword-mode 1)
              ;;(hs-minor-mode 0)
              ;;(c-set-style "gnu")
              (c-toggle-auto-newline 0)
              (c-toggle-auto-hungry-state 0)
              (c-toggle-syntactic-indentation 1)
              ;;(highlight-indentation-mode 1)
              (which-function-mode 1)
              (local-set-key "\C-co" 'ff-find-other-file)
              ;;(my-c-mode-common-hook-if0)
              (setq c-basic-offset 4))))

irony installation

irony-mode is developed by Sarcasm [fn:13]. It is an Emacs minor-mode that aims at improving the editing experience for the C, C++ and Objective-C languages. It works by using a combination of an Emacs package and a C++ program (irony-server) that uses libclang. When correctly configured, it can provide wonderful auto completion for functions and variables. The function prototypes with parameters can be triggered as a yasnippet automatically.

It is quite easy to install irony-server under macOS, just invoke the command “M-x irony-install-server”, and Emacs will compile and install it to ~/.emacs.d/irony/bin/irony-server, by invoking the make commands:

cmake -DCMAKE_INSTALL_PREFIX\=/Users/kimim/.emacs.d/irony/
/Users/kimim/.emacs.d/elpa/irony-20160925.1030/server && cmake --build
. --use-stderr --config Release --target install

For Cygwin/Windows, first we should install libclang 3.8.1-1 and libclang-devel 3.8.1-1 and cmake with setup.exe.

Then compile irony-server with cmake and make:

~/.emacs.d/elpa/irony-20160925.1030/server/build
$ cmake -DCMAKE_INSTALL_PREFIX=~/.emacs.d/irony/ -G "Unix Makefiles" ..

~/.emacs.d/elpa/irony-20160925.1030/server/build
$ make install
Scanning dependencies of target irony-server
[ 14%] Building CXX object src/CMakeFiles/irony-server.dir/support/CommandLineParser.cpp.o
[ 28%] Building CXX object src/CMakeFiles/irony-server.dir/support/TemporaryFile.cpp.o
[ 42%] Building CXX object src/CMakeFiles/irony-server.dir/Command.cpp.o
[ 57%] Building CXX object src/CMakeFiles/irony-server.dir/Irony.cpp.o
[ 71%] Building CXX object src/CMakeFiles/irony-server.dir/TUManager.cpp.o
[ 85%] Building CXX object src/CMakeFiles/irony-server.dir/main.cpp.o
[100%] Linking CXX executable ../bin/irony-server.exe
[100%] Built target irony-server
Install the project...
-- Install configuration: "Release"
-- Up-to-date: /home/kimim/.emacs.d/irony/bin/irony-server.exe

cloljure

(defun org-babel-execute:clojure (body params)
      "Execute a block of Clojure code with Babel.
  The underlying process performed by the code block can be output
  using the :show-process parameter."
      (let* ((expanded (org-babel-expand-body:clojure body params))
             (response (list 'dict))
             result)
        (cl-case org-babel-clojure-backend
          (cider
           (require 'cider)
           (let ((result-params (cdr (assq :result-params params)))
                 (show (cdr (assq :show-process params))))
             (if (member show '(nil "no"))
                 ;; Run code without showing the process.
                 (progn
                   (setq response
                         (let ((nrepl-sync-request-timeout
                                org-babel-clojure-sync-nrepl-timeout))
                           (nrepl-sync-request:eval expanded
                                                    (cider-current-connection))))
                   (setq result
                         (concat
                          (nrepl-dict-get response
                                          (if (or (member "output" result-params)
                                                  (member "pp" result-params))
                                              "out"
                                            "value"))
                          (nrepl-dict-get response "ex")
                          (nrepl-dict-get response "root-ex")
                          (nrepl-dict-get response "err"))))
               ;; Show the process in an output buffer/window.
               (let ((process-buffer (switch-to-buffer-other-window
                                      "*Clojure Show Process Sub Buffer*"))
                     status)
                 ;; Run the Clojure code in nREPL.
                 (nrepl-request:eval
                  expanded
                  (lambda (resp)
                    (when (member "out" resp)
                      ;; Print the output of the nREPL in the output buffer.
                      (princ (nrepl-dict-get resp "out") process-buffer))
                    (when (member "ex" resp)
                      ;; In case there is an exception, then add it to the
                      ;; output buffer as well.
                      (princ (nrepl-dict-get resp "ex") process-buffer)
                      (princ (nrepl-dict-get resp "root-ex") process-buffer))
                    (when (member "err" resp)
                      ;; In case there is an error, then add it to the
                      ;; output buffer as well.
                      (princ (nrepl-dict-get resp "err") process-buffer))
                    (nrepl--merge response resp)
                    ;; Update the status of the nREPL output session.
                    (setq status (nrepl-dict-get response "status")))
                  (cider-current-connection))

                 ;; Wait until the nREPL code finished to be processed.
                 (while (not (member "done" status))
                   (nrepl-dict-put response "status" (remove "need-input" status))
                   (accept-process-output nil 0.01)
                   (redisplay))

                 ;; Delete the show buffer & window when the processing is
                 ;; finalized.
                 (mapc #'delete-window
                       (get-buffer-window-list process-buffer nil t))
                 (kill-buffer process-buffer)

                 ;; Put the output or the value in the result section of
                 ;; the code block.
                 (setq result
                       (concat
                        (nrepl-dict-get response
                                        (if (or (member "output" result-params)
                                                (member "pp" result-params))
                                            "out"
                                          "value"))
                        (nrepl-dict-get response "ex")
                        (nrepl-dict-get response "root-ex")
                        (nrepl-dict-get response "err")))))))
          (slime
           (require 'slime)
           (with-temp-buffer
             (insert expanded)
             (setq result
                   (slime-eval
                    `(swank:eval-and-grab-output
                      ,(buffer-substring-no-properties (point-min) (point-max)))
                    (cdr (assq :package params))))))
          (lein-exec
           (let ((result-params (cdr (assq :result-params params))))
             (if (or (member "output" result-params)
                     (member "pp" result-params))
                 (write-region (concat "(use 'clojure.pprint)
  " expanded) nil "tmp.clj")
               (write-region (concat "(use 'clojure.pprint)
  (clojure.pprint/pprint
    (do " expanded "))") nil "tmp.clj"))
             (setq result
                   (replace-regexp-in-string
                    "
" ""
                    (shell-command-to-string (concat "cat tmp.clj | lein exec")))))))
        (org-babel-result-cond (cdr (assq :result-params params))
          result
          (condition-case nil (org-babel-script-escape result)
            (error result)))))

dired-collapse

It will be difficult to mark the parent directory. Thus let’s disable this extention now.

(use-package dired-collapse)

selectrum

(use-package selectrum-prescient
  :config
  (selectrum-prescient-mode +1)
  (prescient-persist-mode +1))
(use-package marginalia
  :bind (:map minibuffer-local-map
         ("M-A" . marginalia-cycle))

  ;; The :init configuration is always executed (Not lazy!)
  :init
  (marginalia-mode)

  ;; When using Selectrum, ensure that Selectrum is refreshed when cycling annotations.
  (advice-add #'marginalia-cycle :after
              (lambda () (when (bound-and-true-p selectrum-mode) (selectrum-exhibit)))))
(use-package selectrum
  :defer 1
  :config
  (selectrum-mode +1)
  (use-package selectrum-prescient)
  (selectrum-prescient-mode +1)
  (prescient-persist-mode +1)
  (use-package marginalia)
  (marginalia-mode +1))

package

original elpa’s:

;; upstream
(setq package-archives
      '(("gnu" . "https://elpa.gnu.org/packages/")
        ("melpa" . "https://melpa.org/packages/")
        ("org" . "https://orgmode.org/elpa/")))
;; tsinghua mirror
(setq package-archives
      '(("gnu" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/gnu/")
        ("melpa" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/melpa/")
        ("org" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/org/")))

Tagging

(use-package ggtags
  :bind (("C-c f" . ggtags-find-file))
         ;;("M-." . ggtags-find-tag-dwim)
         ;;("M-*" . pop-tag-mark))
  :config
  ;; (use-package ggtags)
  ;; (add-hook 'c-mode-hook 'ggtags-mode)
  ;; (add-hook 'c++-mode-hook 'ggtags-mode)

  (setq ggtags-global-ignore-case t)
  (setq ggtags-sort-by-nearness t))

ox-html

do not embed svg in file now.

(defun org-babel-result-to-file (result &optional description)
  "Convert RESULT into an `org-mode' link with optional DESCRIPTION.
  If the `default-directory' is different from the containing
  file's directory then expand relative links."
  (when (stringp result)
    (if (string= "svg" (file-name-extension result))
        (progn
          (with-temp-buffer
            (if (file-exists-p (concat result ".html"))
                (delete-file (concat result ".html")))
            (rename-file result (concat result ".html"))
            (insert-file-contents (concat result ".html"))
            (message (concat result ".html"))
            (format "#+BEGIN_HTML
  <div style=\"text-align: center;\">
  %s
  </div>
  #+END_HTML"
                    (buffer-string)
                    )))
      (progn
        (format "[[file:%s]%s]"
                (if (and default-directory
                         buffer-file-name
                         (not (string= (expand-file-name default-directory)
                                       (expand-file-name
                                        (file-name-directory buffer-file-name)))))
                    (expand-file-name result default-directory)
                  result)
                (if description (concat "[" description "]") ""))))))

Dealing with Unicode fonts

(use-package unicode-fonts
  :defer 3
  :config
  (defun unicode-fonts-setup-advice ()
    (if window-system
        (set-fontset-font
         "fontset-default"
         'cjk-misc (font-spec :family "YaheiInconsolata"))))
  (advice-add 'unicode-fonts-setup :after 'unicode-fonts-setup-advice)
  (defun kimim/add-font (group font)
    (let ((font-list (assoc group unicode-fonts-block-font-mapping)))
      (setf (cadr font-list) (cons font (cadr font-list)))))
  (seq-map (lambda (group) (kimim/add-font group "YaheiInconsolata"))
           '("Bopomofo" "Bopomofo Extended" "CJK Compatibility" "CJK Compatibility Forms"
             "CJK Compatibility Ideographs" "CJK Compatibility Ideographs Supplement"
             "CJK Radicals Supplement" "CJK Strokes" "CJK Symbols and Punctuation"
             "CJK Unified Ideographs" "CJK Unified Ideographs Extension A"
             "CJK Unified Ideographs Extension B" "CJK Unified Ideographs Extension C"
             "CJK Unified Ideographs Extension D" "CJK Unified Ideographs Extension E"
             "Enclosed Ideographic Supplement" "Halfwidth and Fullwidth Forms"
             "Hangul Compatibility Jamo" "Hangul Jamo" "Hangul Jamo Extended-A"
             "Hangul Jamo Extended-B" "Hangul Syllables" "Ideographic Description Characters"
             "IPA Extensions" "Mathematical Alphanumeric Symbols"))
  (seq-map (lambda (group) (kimim/add-font group "Consolas"))
           '("Combining Diacritical Marks" "Combining Half Marks" "Cyrillic"
             "Cyrillic Supplement" "Greek Extended" "Greek and Coptic" "Phonetic Extensions"
             "Phonetic Extensions Supplement" "Superscripts and Subscripts"))
  (add-to-list 'unicode-fonts-block-font-mapping
               '("Spacing Modifier Letters"
                 ("Consolas" "Monaco" "YaheiInconsolata")))
  (unicode-fonts-setup))

org link: deft

C-x l keychord can store deft links in deft mode, but cannot fetch the link from deft note. Below defines a function to fetch a deft style link, which can be used to paste directly in other org files, such as work journal. Buffer file name handling function can be found from emacs manual[fn:22].

(use-package org
  :bind
  (("C-x m d" . kimim/deft-store-link))
  :config
  (defun kimim/deft-store-link()
    "get deft link of current note file."
    (interactive)
    (unless (buffer-file-name)
      (error "No file for buffer %s" (buffer-name)))
    (let ((msg (format "[[deft:%s]]"
                       (file-name-nondirectory (buffer-name)))))
      (kill-new msg)
      (message msg))))

sunrise commander

The Sunrise Commmander is a powerful and versatile double-pane file manager for GNU Emacs. It’s built atop of Dired and takes advantage of most of its functions, but also provides many handy features of its own.

To list directories first, you need to set ls-lisp-dirs-first to non-nil. [fn:11]

(use-package sunrise-commander
  :bind (("<f10>" . sunrise)
         :map sr-mode-map
         ("D" . dired-do-delete)
         ("<f2>" . nil)
         ("o" . kimim/open-external)
         ("b" . sr-dired-prev-subdir)
         ("<left>" . sr-dired-prev-subdir)
         ("<right>" . sr-advertised-find-file))
  :custom
  (sr-cursor-follows-mouse nil)
  (sr-windows-default-ratio 80)
  (sr-listing-switches "-AGhlgov")
  (sr-attributes-display-mask '(nil nil nil t t t))
  (sr-show-file-attributes nil)
  :config
  (require 'dired)
  (if (eq system-type 'darwin)
      (setq sr-listing-switches "-Ahlgo")))

tldr

TL;DR stands for “Too Long; Didn’t Read”[fn:9]. tldr.el [fn:10] is the Emacs client.

(use-package tldr)

org agenda

  (add-hook 'org-agenda-after-show-hook 'org-narrow-to-subtree)
  (defun org-agenda-add-note (&optional arg)
    "Add a time-stamped note to the entry at point. DO NOT show other
headers when adding notes"
    (interactive "P")
    (org-agenda-check-no-diary)
    (let* ((marker (or (org-get-at-bol 'org-marker)
		               (org-agenda-error)))
	       (buffer (marker-buffer marker))
	       (pos (marker-position marker))
	       (hfdmarker (org-get-at-bol 'org-hd-marker))
	       (inhibit-read-only t))
      (with-current-buffer buffer
        (org-narrow-to-subtree) ;; change from widen to org-narrow-to-subtree
        (goto-char pos)
        (org-show-context 'agenda)
        (org-add-note))))