svg-tag-mode

被大神惊呆了,将 Org-mode 里的 TAG 转成 SVG 图片格式,而且可以自己定义。

Rougier 太强了,而且想法非常不受限制,值得学习。

rougier/svg-tag-mode: A minor mode for Emacs that replace keywords with nice SVG labels GitHub - rougier/svg-tag-mode: A minor mode for Emacs that replace keywords with nice SVG labels.

实践下来生成的图片没有他演示文档里那么好看,出现了错位、占位宽度等等细节问题

2 个赞

Agree, 我用了下,要真弄得很美观的话,要花很多功夫去调整,默认开启的话并不好看

同意楼上,Rougier的包好看是真的好看 (要想融入自己的配置也真的很麻烦

这个大神真艺术家啊,好想从他那里分一点艺术细菌。。。

法国人,应该是天生的吧,一边搞科研,一边还可以搞美化 Emacs 的事儿

最近还是尝试了下 svg-tag-mode ,确实坑很多,比如说需要自己细调位置、和 varable-pitch-mode 不兼容、会破坏 infofont-lock、还有无法在 org-agenda 下显示… 不过好在折腾下后都顺利解决了,效果确实不错:

image

2 个赞

可以分享一波啊

这个问题我在 issue: Some tags not rendering in org-agenda 里面解释了,主要是 org-agenda 不用 font-lock-mode 的问题,我的方案是用 overlay

  (defun eli-org-agenda-show-svg ()
    (let* ((case-fold-search nil)
           (keywords (mapcar #'svg-tag--build-keywords svg-tag--active-tags))
           (keyword (car keywords)))
      (while keyword
        (save-excursion
          (while (re-search-forward (nth 0 keyword) nil t)
            (overlay-put (make-overlay
                          (match-beginning 0) (match-end 0))
                         'display  (nth 3 (eval (nth 2 keyword)))) ))
        (pop keywords)
        (setq keyword (car keywords)))))
(add-hook 'org-agenda-finalize-hook #'eli-org-agenda-show-svg)

这应该是 bug ,我还没提 issue ,解决方法是:

  (add-hook 'org-mode-hook (lambda ()
                               (make-local-variable 'font-lock-extra-managed-props)
                               (svg-tag-mode)))

这个比较 tricky ,svg-lib 计算图片位置的方式我没仔细研究,不是很清楚,所以直接魔改了函数 svg-lib-tag ,让它用 fixed-pitch 的高度和宽度,同时接受 :ascent 参数,方便后续位置调整:

  (defun svg-lib-tag (label &optional style &rest args)
    "Create an image displaying LABEL in a rounded box using given STYLE
and style elements ARGS."

    (let* ((default svg-lib-style-default)
           (style (if style (apply #'svg-lib-style nil style) default))
           (style (if args  (apply #'svg-lib-style style args) style))

           (foreground  (plist-get style :foreground))
           (background  (plist-get style :background))

           (crop-left   (plist-get style :crop-left))
           (crop-right  (plist-get style :crop-right))

           (alignment   (plist-get style :alignment))
           (stroke      (plist-get style :stroke))
           ;; (width       (plist-get style :width))
           (height      (plist-get style :height))
           (radius      (plist-get style :radius))
           ;; (scale       (plist-get style :scale))
           (margin      (plist-get style :margin))
           (padding     (plist-get style :padding))
           (font-size   (plist-get style :font-size))
           (font-family (plist-get style :font-family))
           (font-weight (plist-get style :font-weight))
           
           ;; use `fixed-pitch' while in `mixed-pitch-mode'
           (txt-char-width  (window-font-width nil 'fixed-pitch))
           (txt-char-height (window-font-height nil 'fixed-pitch))
           (txt-char-height (if line-spacing
                                (+ txt-char-height line-spacing)
                              txt-char-height))
           (font-info       (font-info (format "%s-%d" font-family font-size)))
           (font-size       (aref font-info 2)) ;; redefine font-size
           ;; (ascent          (aref font-info 8))
           (ascent          (plist-get style :ascent))
           (tag-char-width  (aref font-info 11))
           ;; (tag-char-height (aref font-info 3))
           (tag-width       (* (+ (length label) padding) txt-char-width))
           (tag-height      (* txt-char-height height))

           (svg-width       (+ tag-width (* margin txt-char-width)))
           (svg-height      tag-height)

           (tag-x  (* (- svg-width tag-width)  alignment))
           (text-x (+ tag-x (/ (- tag-width (* (length label) tag-char-width))
                               2)))
           (text-y ascent)

           (tag-x      (if crop-left  (- tag-x     txt-char-width) tag-x))
           (tag-width  (if crop-left  (+ tag-width txt-char-width) tag-width))
           (text-x     (if crop-left  (- text-x (/ stroke 2)) text-x))
           (tag-width  (if crop-right (+ tag-width txt-char-width) tag-width))
           (text-x     (if crop-right (+ text-x (/ stroke 2)) text-x))
           
           (svg (svg-create svg-width svg-height)))

      (if (>= stroke 0.25)
          (svg-rectangle svg tag-x 0 tag-width tag-height
                         :fill foreground :rx radius))
      (svg-rectangle svg (+ tag-x (/ stroke 2.0)) (/ stroke 2.0)
                     (- tag-width stroke) (- tag-height stroke)
                     :fill background :rx (- radius (/ stroke 2.0)))
      (svg-text svg label
                :font-family font-family :font-weight font-weight
                :font-size font-size :fill foreground :x text-x :y  text-y)
      (svg-lib--image svg :ascent 'center)))

至于这点,svg 图片位置受很多因素影响,每个人的配置不同,问题和需求也不同,需要自己慢慢调。

欢迎大家补充。

4 个赞

日期的配置在doom中报错,没办法显示。 你的日期显示是用的example 2 的配置吗?

是,不过补充了 repeat tasks 的正则等一些小改动

我不用 Doom ,不过可以把报错信息贴出来看看

这东东看起来很美,用起来太困难,稍微变下就要改很久。需要更好的更简单的包装才行。

同意,而且他这些图片参数和 Emacs 文档里的图片参数说明有点不一样,甚至有些能传递有些不能传递,还把 line-spacing 给包含进去了,基本上很难开箱即用,都要结合自己的配置调整细节。我调整后整个相关配置有两百多行,属实有点过于 hack 了。

不过如果能接受这点,带来的视觉效果提升还是很明显的。

这种还是需要进入核心库才会有更好的发展。只有更多的包支持才可能有好的生态。当然,前提是更易用。看看有没有杀手级的包出现。org-modern其实是一个好的起点 :joy: