零基础Emacs-lisp学习笔记

工程师到了施工现场首先需要工具,

有了工具便能将项目现场的材料与设备模块成电气系统, 通风系统, 空调系统, 管道工程, 电梯工程, 消防工程, 安防工程, 以及智能化监控系统; 集成模块, 交付产品. 工具有四件:

  1. Expression(operator)
  2. Variable
  3. Function
  4. Control
  • Expression

      #+begin_src emacs-lisp :session engineer :lexical t
      (+ (* 3 5) (- 10 6))
      #+end_src
      #+RESULTS:
      : 19
    
  • Variable

     #+begin_src emacs-lisp :session engineer :lexical t
     (defvar pi 3.14159)
     (defvar radius 10)
     (defvar circumference (* 2 pi radius))
      circumference
     #+end_src
    
     #+RESULTS:
     : 62.83185307179586
    
    
  • Function

     #+begin_src emacs-lisp :session engineer :lexical t
     (defun square (x) (* x x))
     (square 36)
     #+end_src
    
     #+RESULTS:
     : 1296
    
  • Control

#+begin_src emacs-lisp :session engineer :lexical t
(defun abs(x)
(cond ((> x 0) x)
      ((= x 0) 0)
      ( t (< x 0) (- x))
))
(abs -10)
#+end_src

#+RESULTS:
: 10
#+begin_src emacs-lisp :session engineer :lexical t
(defun abs(x)
(if (< x 0)
(- x)
x))
(abs -9)
#+end_src

#+RESULTS:
: 9

工具齐备, 接踵而来的事情是如何运用工具操控设备与加工材料:
主要材料是Emacs的Frame, Window, Buffer, File, Mode, Point, Keys…
以及种种被成为Extensions的机器设备.

https://github.com/AbstProcDo/Build-Things-with-Elisp

4 个赞

01."材料"加工之初窥

既然工具箱里, 已经装满了全部的工具, 马上开动加工材料.

(+ 1
   (/ 1 1.618))

(setq evil-default-state 'emacs)

(defun insert-current-date ()
  "Insert the current date"
  (interactive "*")
  (insert (format-time-string "%Y-%m-%d %A" (current-time)))
  )

(if (display-graphic-p)
    (progn
      ;;if graphic
      (dolist (charset '(kana han symbol cjk-misc bopomofo))
        (set-fontset-font
         (frame-parameter nil 'font)
         charset
         (font-spec :name "-ADBE-思源黑体"
                    :weight 'normal
                    :slant 'normal
                    :size 15.0)))
      )
  ;;else (optional)
  )
1 个赞

;; Captrue words
(require 'thingatpt)

(defun my-append-word ()
  (interactive)
  (let ((word (if (not (region-active-p))
                  (word-at-point)
                (buffer-substring (region-beginning) (region-end)))))
    (with-current-buffer (find-file-noselect "~/Documents/OrgMode/ORG/src/build-vocabulary.org")
      (goto-char (point-max))
      (insert word "\n")
      (save-buffer))))

应用"以终为始"的思路, 手工操作的六步, 其中后半段的三步是:
3. C-x C-f (M-x find-file) 找到文件build-vocabulary.org, 读取到buffer中.
4. M-> 光标移动到Buffer最末行,
5. C-y 黏贴

正好对应:

  (with-current-buffer (find-file-noselect "~/Documents/OrgMode/ORG/src/build-vocabulary.org")
      (goto-char (point-max))
      (insert word "\n")
      (save-buffer))))

  (with-current-buffer (find-file-noselect "~/Documents/OrgMode/ORG/src/build-vocabulary.org")
      (goto-char (point-max))
      (insert word "\n")
      (save-buffer))))

let定义local variable, region-active-p, p是predicate, 前文见到了.
如果没有选择一块region, 则将光标处的单词给Word,
如果有选中的操作,则将region复制给Word.

最后一个
: (interactive)
是Emacs最有魅力之处, 刚才定义的function可以C-x直接调用.

在C-h f的帮助下, 似乎就跟文科的地理课开卷考试一样.

2 个赞

03.Select a Sentence

M-x append-to-word, 将选中的单词或者句子推送到 build-vocabulary.org.

选中一个单词, 同时按Ctrl-Meta-Space,
而选中一个句子需要多个步骤,

  1. Ctrl-Meta-Space, 持续按键Space, 却不能在断句处止步
  2. C-@ 组合M-f (word-forward), 也是逐个选中.

能不能一步完成呢? 如果写一个大概思路 1) 找断句的.?等 2) 选中.

Google或者SO提问, 找到 =mark-end-of-sentence= 可以M-x mark-end-of-sentence调用, 也可以绑定到, M-C-s (跟M-C-Space)对应.

学习下这个函数

#+begin_src emacs-lisp :session learn :lexical t
(defun mark-end-of-sentence (arg)
  "Put mark at end of sentence.  Arg works as in `forward-sentence'.
If this command is repeated, it marks the next ARG sentences after the
ones already marked."
  (interactive "p")
  (push-mark
   (save-excursion
     (if (and (eq last-command this-command) (mark t))
	 (goto-char (mark)))
     (forward-sentence arg)
     (point))
   nil t))

另外看看=sentence-end=

(defun sentence-end ()
  "Return the regexp describing the end of a sentence.

This function returns either the value of the variable `sentence-end'
if it is non-nil, or the default value constructed from the
variables `sentence-end-base', `sentence-end-double-space',
`sentence-end-without-period' and `sentence-end-without-space'.

The default value specifies that in order to be recognized as the
end of a sentence, the ending period, question mark, or exclamation point
must be followed by two spaces, with perhaps some closing delimiters
in between.  See Info node `(elisp)Standard Regexps'."
  (or sentence-end
      ;; We accept non-break space along with space.
      (concat (if sentence-end-without-period "\\w[ \u00a0][ \u00a0]\\|")
	      "\\("
	      sentence-end-base
              (if sentence-end-double-space
                  "\\($\\|[ \u00a0]$\\|\t\\|[ \u00a0][ \u00a0]\\)" "\\($\\|[\t \u00a0]\\)")
              "\\|[" sentence-end-without-space "]+"
	      "\\)"
              "[ \u00a0\t\n]*")))

整理org-note配置


;;; ~/Documents/primary.doom.d/my-config/my-org-note.el -*- lexical-binding: t; -*-


;;-------------------------------------------------------------------
;; Org Note
;; ------------------------------------------------------------------
;; Org Note最核心的一点是大纲结构.
;;links
;; internal links of org
(setq org-link-search-must-match-exact-headline nil)

;;Tables
;;添加首列
(defun +org/table-insert-column-left () ;;question? 命名方式?
  "Insert a new column left of the current column."
  (interactive)
  (org-table-insert-column)
  (org-table-move-column-left))


;; Captrue words
(require 'thingatpt)

(defun my-append-word ()
  (interactive)
  (let ((word (if (not (region-active-p))
                  (word-at-point)
                (buffer-substring (region-beginning) (region-end)))))
    (with-current-buffer (find-file-noselect "~/Documents/OrgMode/ORG/src/build-vocabulary.org")
      (goto-char (point-max))
      (insert word "\n")
      (save-buffer))))

;;Images
;;
;;live refresh inline images
(add-hook 'org-babel-after-execute-hook 'org-display-inline-images)
;;org-mode显示图片
(setq org-image-actual-width nil)
(add-hook 'org-mode-hook (lambda ()
                           (org-display-inline-images t)))
;;live refresh inline images
(add-hook 'org-babel-after-execute-hook 'org-display-inline-images)

;;Disable auto-fill-mode
(add-hook 'org-mode-hook (lambda ()
                           (auto-fill-mode -1)))


;;------------------------------------------------------------------------
;; Screenshot ;;总感觉不是一个正式的单词.
;;------------------------------------------------------------------------

;; Rahul Org-mode Screenshot takes a screenshot with scrot -s (waits for screen
;; selection), saves it as orgfileopened.org_YYYYMMDD_hhmmss.png, inserts
;; the link and turns on the display-inline-images, showing your screenshot directly
;; to the org-file"
(add-hook 'org-mode-hook (lambda ()
                           (defun ros ()
                             (interactive)
                             (if buffer-file-name (progn (message
                                                          "Waiting for region selection with mouse...")
                                                         (let ((filename (concat "../images/"
                                                                                 (file-name-nondirectory
                                                                                  buffer-file-name)
                                                                                 "_"
                                                                                 (format-time-string
                                                                                  "%Y%m%d_%H%M%S")
                                                                                 ".png")))
                                                           (if (executable-find "scrot")
                                                               (call-process "scrot" nil nil nil
                                                                             "-s" filename)
                                                             (call-process "screencapture" nil nil
                                                                           nil "-s" filename))
                                                           (insert (concat "[[" filename "]]"))
                                                           (org-display-inline-images t t))
                                                         (message "File created and linked..."))
                               (message "You're in a not saved buffer! Save it first!")))))

(provide 'my-org-note)
;; end of <my-org-note>

整理org-todo(agenda)

 ;;; ~/Documents/primary.doom.d/my-config/my-org-agenda.el -*- lexical-binding: t; -*-

;;-------------------------------------------------------------------
;; 1) Org Todos
;; ------------------------------------------------------------------

(setq org-log-done t)

(defun org-current-is-todo ()
  (string= "TODO" (org-get-todo-state)))

;;Capture Notes and Tasks
(defun my-org-goto-last-personal-notes-headline ()
  "Move point to the last headline in file matching \"** Personal_Note\"."
  (end-of-buffer)
  (re-search-backward "\\*\\* Personal_Notes"))

(defun my-org-goto-last-personal-tasks-headline ()
  "Move point to the last headline in file matching \"** Personal_Tasks\"."
  (end-of-buffer)
  (re-search-backward "\\*\\* Personal_Tasks"))

(defun my-org-goto-last-project-notes-headline ()
  "Move point to the last headline in file matching \"** Tasks\"."
  (end-of-buffer)
  (re-search-backward "\\*\\* Project_Notes"))

(defun my-org-goto-last-project-tasks-headline ()
  "Move point to the last headline in file matching \"**** Tasks\"."
  (end-of-buffer)
  (re-search-backward "\\*\\* Project_Tasks"))

(setq org-capture-templates
      '(("n" "Personal Note" entry
         (file+function "~/Documents/OrgMode/ORG/src/todo.today.org"
                        my-org-goto-last-personal-notes-headline)
         "* %T %?")
        ("t" "Personal Todo" entry
         (file+function "~/Documents/OrgMode/ORG/src/todo.today.org"
                        my-org-goto-last-personal-tasks-headline) "* TODO %i%?")

        ("pn" "Project Note" entry
         (file+function "~/Documents/OrgMode/ORG/src/todo.today.org"
                        my-org-goto-last-project-notes-headline)
         "* %T %?")
        ("pt" "Project Todo" entry
         (file+function "~/Documents/OrgMode/ORG/src/todo.today.org"
                        my-org-goto-last-project-tasks-headline) "* TODO %i%?")


        ("T" "Tickler" entry
         (file+headline "~/Documents/OrgMode/ORG/src/tickler.org" "Tickler") "* %i%? \n %U")))




;;--------------------------------------
;;2) Agenda View
;;--------------------------------------
;;;;(setq org-agenda-start-day "-1d")
(setq org-agenda-start-day "+0d")
(setq org-agenda-span 1)
(setq org-agenda-start-on-weekday 1)


;;---------------------------------------------
;;org-agenda-time-grid
;;--------------------------------------------
(setq org-agenda-time-grid (quote ((daily today require-timed)
                                   (300
                                    600
                                    900
                                    1200
                                    1500
                                    1800
                                    2100
                                    2400)
                                   "......"
                                   "-----------------------------------------------------"
                                   )))

(setq org-agenda-files '("~/Documents/OrgMode/ORG/src/";;2019-06-18 13:37:12
                         ))

;;Agenda Todo List
(setq org-agenda-custom-commands
      '(
        ("t" tags-todo  "-habit-schedule")
        ;;("t" tags-todo  "-schedule") 无效的写法.
        ))

;;---------------------------------------------------------------------
;;3) 时间管理的三件武器之Clock
;;Org clock and time
;;---------------------------------------------------------------------
;;Save the running clock and all clock history when exiting Emacs, load it on startup
(with-eval-after-load 'org (org-clock-persistence-insinuate))
(setq org-clock-persist t)
(setq org-clock-in-resume t)

;;Save clock data and notes in the LOGBOOK drawer
(setq org-clock-into-drawer t)
;;Save state changes in the LOGBOOK drawer
(setq org-log-into-drawer t)
;;Removes clocked tasks with 0:00 duration
(setq org-clock-out-remove-zero-time-clocks t)

;;Show clock sums as hours and minutes, not "n days" etc.
(setq org-time-clocksum-format
      '(:hours "%d"
               :require-hours t
               :minutes ":%02d"
               :require-minutes t))

;;
;; 抬头处显示clock时间.
;;; Show the clocked-in task - if any - in the header line
(defun sanityinc/show-org-clock-in-header-line ()
  (setq-default header-line-format '((" " org-mode-line-string " "))))

(defun sanityinc/hide-org-clock-from-header-line ()
  (setq-default header-line-format nil))

(add-hook 'org-clock-in-hook 'sanityinc/show-org-clock-in-header-line)
(add-hook 'org-clock-out-hook 'sanityinc/hide-org-clock-from-header-line)
(add-hook 'org-clock-cancel-hook 'sanityinc/hide-org-clock-from-header-line)

(with-eval-after-load'org-clock (define-key org-clock-mode-line-map [header-line mouse-2]
                                  'org-clock-goto)
                                (define-key org-clock-mode-line-map [header-line mouse-1]
                                  'org-clock-menu))

;;
;;
;;Insert timestamp
(defun insert-current-date ()
  "Insert the current date"
  (interactive "*")
  (insert (format-time-string "%Y-%m-%d %A" (current-time)))
  )
;;(format-time-string "%a-%b-%d %p %H:%M" (current-time));;标准的格式

(defvar insert-time-format "%X"
          "*Format for \\[insert-time] (c.f. format-time-string').")

 (defvar insert-date-format "%x"
           "*Format for \\[insert-date] (c.f. 'format-time-string').")

;;------------------------------------------------------------------
;;4. Org with dairy
;;------------------------------------------------------------------
(setq org-agenda-include-diary t)
(setq org-agenda-diary-file "~/Documents/OrgMode/ORG/src/sdiary.org")

(add-to-list 'org-modules 'org-tempo)



;;
;;Projects
;;(setq org-stuck-projects '("+PROJECT/-DONE" ("NEXT" "TODO") ))



(provide 'my-org-agenda)
;;ends of 'my-org-agenda
1 个赞

有劳费心, 投我一票 (比心

04.半点报时

工作中往往意识不到"时间的流逝",
比如修正一个无关痛痒的bug, 常常伏案从日落见日出.

个中问题, 并非没有意识到不应该投入海量的时间于"鸡毛蒜皮"的事情之上, 而是身不由己, 忘记了"低头看表".
对此问题的解决方案,
有人建议戴手环. 试过几款手环, 不胜其扰.

本节提供一个完美的解决方案: 半点报时, 强制暂停, 强制感受时间的流逝.

;;Report time every half hour
(defun announce-time ()
  (message-box (format "It's %s" (format-time-string "%I:%M %p" (current-time)))))

(let ((next-hour
       (number-to-string
        (+ (string-to-number
            (format-time-string "%H" (current-time)))
           1))))
  (run-at-time (concat next-hour ":00") 1800 #'announce-time))

基本逻辑:在当前时间的下一个整点开始运行半点报时, 比如"早晨6:15"打开Emacs, 则从7:00开始报时, 每半个小时报时一次.

整点或者整半点, 弹出报时窗口, 强制暂停, 必须关闭提醒窗口才能继续操作.

可以运行M-x list-timers, 查看当前的活跃的计时任务.

        2.30        - undo-auto--boundary-timer
       11.23     1.00 display-time-event-handler
     1451.23    30.00 announce-time
     2527.06    60.00 url-cookie-write-file
*       0.05        t aggressive-indent--indent-if-changed
*       0.10        t highlight-indent-guides--try-update-line-cache
*       0.10        t show-paren-function
*       0.20        t org-indent-initialize-agent
*       0.50        t jit-lock-context-fontify
*       1.00        t which-key--update
*       1.00        t amx-idle-update
*       5.00  :repeat save-some-buffers
*      10.00        t gcmh-idle-garbage-collect

所属项目: Build Things with elisp

2 个赞

写的挺好的啊, github的项目删掉了吗? 怎么不继续写了?