[更新] tp.el 自定义文本属性、调色盘 和 响应式文本

tp.el 更新了下面三个功能:

自定义文本属性

tp.el 提供了 define-tp 宏来自定义文本属性,自定义文本属性可以使用内置的文本属性组合并设置适当的参数来使得文本属性的使用更加简单,方便复用。定义完成后,就可以像内置的文本属性那样进行设置。

比如下面两个自定义文本属性:

;; 定义单位或像素间距
(define-tp tp-space (width)
  `(display (space :width ,width)))

;; 定义文本上按键/鼠标行为
;; 值为函数时,默认表示绑定函数到 "[mouse-1]" 和 回车按键上
;; 值为plist: '(:keys ("a" "b") :action <function>) 表示指定按键和函数
(define-tp tp-action (sexp)
  ;; SEXP is a function or plist
  (let (action keys)
    (if (functionp sexp)
        (progn
          (setq action sexp)
          (setq keys `(,(kbd "RET") [mouse-1])))
      (setq action (plist-get sexp :action))
      (setq keys (or (plist-get sexp :keys)
                     `(,(kbd "RET") [mouse-1]))))
    `( keymap ,(let ((keymap (make-sparse-keymap)))
                 (dolist (key keys)
                   (define-key keymap key action))
                 keymap)
       rear-nonsticky (keymap))))

使用上面的两个自定义文本属性:

(tp-set " " 'tp-space '(10))
;; #(" " 0 1 (display (space :width (10))))

(defun tp-test-action-trigger ()
  (interactive)
  (message "%s clicked!" (this-command-keys)))

(tp-pop-to-buffer "*tp-test-action*"
  (insert
   (tp-set "click me"
           'face '(:box t)
           'pointer 'hand
           'tp-action 'tp-test-action-trigger)))

(tp-pop-to-buffer "*tp-test-action*"
  (insert
   (tp-set "click me"
           'face '(:box t)
           'tp-action '( :keys ("a" "b")
                         :action tp-test-action-trigger))))

如果定义的文本属性定义时参数为空,表示使用 t 和 nil 来设置和取消。tp.el 的最后提供了更多的自定义文本属性可用于参考。

调色盘系统

Palette(调色盘) 指的是一组在亮色和暗色主题下都能很好显示的颜色组合,目的是使emacs中颜色设置更加简单方便。使用 define-tp-palette 进行定义,定义格式如下:

(define-tp-palette success
  :fg ("#1a7f37" . "#3fb950") :bg ("#dafbe1" . "#1b4721")
  :border ("#4ac26b" . "#238636"))

:fg, :bg, :border 分别表示前景色,背景色和边框颜色,cons-cell 中的 car 部分是亮色主题背景下的颜色,cdr 部分是暗色主题背景下的颜色。tp-palette.el 中内置了更多已经定义好的 palette,用户也可以按照需要自行定义。

然后我们可以使用 'tp-palette 文本属性来设置定义好的 palette 值,默认会设置 define-tp-palette 中定义的所有(fg,bg,border)文本属性,如果需要单独设置 前景/背景/边框颜色,只需在palette值加上 “-fg/-bg/-fbg/-border” 后缀。使用 tp-palette-show 这个交互命令会展示所有定义好的调色盘。

下面是例子:

(defun tp-test-palette-string (string palette)
  (tp-set
   (concat (tp-set " " 'tp-space '(6)) string
           (tp-set " " 'tp-space '(6)))
   'tp-palette palette))

(tp-pop-to-buffer "*tp-test-palette*"
  (insert
   (tp-test-palette-string "success" 'success) " "
   (tp-test-palette-string "warning" 'warning) " "
   (tp-test-palette-string "error" 'error) " "
   (tp-test-palette-string "info" 'info) " "
   (tp-test-palette-string "neutral" 'neutral) "\n\n"
   (tp-test-palette-string "success-fg" 'success-fg) " "
   (tp-test-palette-string "warning-bg" 'warning-bg) " "
   (tp-test-palette-string "error-fbg" 'error-fbg) " "
   (tp-test-palette-string "info-border" 'info-border) "\n\n"
   (tp-test-palette-string "rainbow-1" 'rainbow-1) " "
   (tp-test-palette-string "rainbow-2" 'rainbow-2) " "
   (tp-test-palette-string "rainbow-3" 'rainbow-3) " "
   (tp-test-palette-string "rainbow-4" 'rainbow-4) " "
   (tp-test-palette-string "rainbow-5" 'rainbow-5) " "
   (tp-test-palette-string "rainbow-6" 'rainbow-6) " "
   (tp-test-palette-string "rainbow-7" 'rainbow-7) "\n\n"
   (tp-test-palette-string "⬛" 'heatmap-g0)
   (tp-test-palette-string "⬛" 'heatmap-g1)
   (tp-test-palette-string "⬛" 'heatmap-g2)
   (tp-test-palette-string "⬛" 'heatmap-g3)
   (tp-test-palette-string "⬛" 'heatmap-g4) "\n"
   (tp-test-palette-string "⬛" 'heatmap-h0)
   (tp-test-palette-string "⬛" 'heatmap-h1)
   (tp-test-palette-string "⬛" 'heatmap-h2)
   (tp-test-palette-string "⬛" 'heatmap-h3)
   (tp-test-palette-string "⬛" 'heatmap-h4)))

响应式文本

响应式文本让buffer中文本具备动态变化的特性,即当文本绑定到的变量的值变化的时候,buffer中文本会自动增量更新。使用方法是设置一个特殊的 'tp-text 文本属性,该文本属性的值会在渲染时替换原始的文本,再结合已经实现的响应式变量就可以实现响应式文本。

(tp-set "original text"
        'tp-text (tp-set "new text" 'tp-palette 'warning))

;; 实际渲染的文本是 "new text"
;; #("new text" 0 8 (tp-text #("new text" 0 8 (face (:foreground "#d29922" :background "#3d2e00" :box (:color "#9e6a03")))) face (:foreground "#d29922" :background "#3d2e00" :box (:color "#9e6a03"))))

使用响应式变量结合 'tp-text 的例子:

(defvar tp-test-toogle-flag "ON")

(defun tp-test-toggle ()
  (interactive)
  (if (string= tp-test-toogle-flag "ON")
      (progn
        (setq-local tp-test-toogle-flag "OFF")
        (message "toggle on!"))
    (setq-local tp-test-toogle-flag "ON")
    (message "toggle off!")))

(tp-pop-to-buffer "*tp-test-toggle*"
  (insert
   "this is a toggle: "
   (tp-set
    "ON" 'tp-text '$tp-test-toogle-flag
    'tp-palette 'success
    'pointer 'hand
    'tp-action 'tp-test-toggle)))

tp-test-text

11 个赞