Emacs可以为elisp字符串常量提供支持吗?

时间:2013-07-12 16:54:21

标签: emacs elisp

困境:可读性还是可维护性?

让我们看看以下功能。 它的作用并不重要,重要的是它 它使用了两次字符串"(let\\*?[ \t]*"

(defun setq-expression-or-sexp ()
  "Return the smallest list that contains point.
If inside VARLIST part of `let' form,
return the corresponding `setq' expression."
  (interactive)
  (ignore-errors
    (save-excursion
      (up-list)
      (let ((sexp (preceding-sexp)))
        (backward-list 1)
        (cond
         ((looking-back "(let\\*?[ \t]*")
          (cons 'setq
                (if (= (length sexp) 1)
                    (car sexp)
                  (cl-mapcan
                   (lambda (x) (unless (listp x) (list x nil)))
                   sexp))))
         ((progn
            (up-list)
            (backward-list 1)
            (looking-back "(let\\*?[ \t]*"))
          (cons 'setq sexp))
         (t
          sexp))))))

由于在两个(或更多)位置更新字符串很头疼, 我必须这样defconst

(defconst regex-let-form "(let\\*?[ \t]*")

虽然代码变得更易于维护,但它的可读性也降低了, 因为很难一眼看出regex-let-form究竟是什么:

(defun setq-expression-or-sexp ()
  "Return the smallest list that contains point.
If inside VARLIST part of `let' form,
return the corresponding `setq' expression."
  (interactive)
  (ignore-errors
    (save-excursion
      (up-list)
      (let ((sexp (preceding-sexp)))
        (backward-list 1)
        (cond
         ((looking-back regex-let-form)
          (cons 'setq
                (if (= (length sexp) 1)
                    (car sexp)
                  (cl-mapcan
                   (lambda (x) (unless (listp x) (list x nil)))
                   sexp))))
         ((progn
            (up-list)
            (backward-list 1)
            (looking-back regex-let-form))
          (cons 'setq sexp))
         (t
          sexp))))))

这个想法:为什么不两者?

因为它是一个常数,为什么不font-lock它 并使regex-let-form看起来好像是"(let\\*?[ \t]*"? 这是一项可行的工作,因为:

  1. 可以像这样对字符串进行字体锁定:http://www.emacswiki.org/emacs/PrettyLambda, 甚至是这样的:rainbow-mode

  2. 并且可以使用字体锁定常量。它已经完成了c ++模式, 但据我所知,目前还没有emacs-lisp-mode。

  3. 然后它仍然只是连接两者。不幸的是,我不知道 足够的font-lock内脏来做,但也许其他人呢? 或者已经有一个包这样做?

4 个答案:

答案 0 :(得分:1)

this answer调整代码, 我已经解决了这个问题:

(font-lock-add-keywords 
 'emacs-lisp-mode
 '((fl-string-constant . 'font-lock-constant-face)) 'append)

(defun fl-string-constant (_limit)
  (while (not 
          (ignore-errors
            (save-excursion
              (skip-chars-forward "'")
              (let ((opoint (point))
                    (obj (read (current-buffer)))
                    obj-val)
                (and (symbolp obj)
                     (risky-local-variable-p obj)
                     (special-variable-p obj)
                     (stringp (setq obj-val (eval obj)))
                     (progn
                       (put-text-property 
                        (1- (point)) (point) 'display
                        (format "%c\"%s\"" (char-before) obj-val))
                       (set-match-data (list opoint (point))) 
                       t))))))
    (if (looking-at "\\(\\sw\\|\\s_\\)")
        (forward-sexp 1)
      (forward-char 1)))
  t)

这将在常量名称后面显示字符串常量的值。 它与精确的字符串常量一起运行得非常好。 速度是一个问题 - 欢迎提出改进建议。

另外,我找不到比risky-local-variable-p更好的东西来确定 这是一个常数。该文档说defconst标记变量 特别危险,但没有别的。

答案 1 :(得分:1)

hl-defined.el(今天更新,2013-10-20)可以突出显示常量Emacs-Lisp符号,即当前值为符号本身的变量。如果您的defconst已经过评估,那么这将按照您的要求进行。

答案 2 :(得分:0)

这似乎有用(来源:http://www.emacswiki.org/emacs/PrettyLambda):

(font-lock-add-keywords 'emacs-lisp-mode
  `(("\\<\\(regex-let-form\\)\\>" (0 (prog1 nil
                                       (compose-region (match-beginning 1)
                                                       (match-end 1)
                                                       "\"(let\\\\*?[ \\t]*\""))))))

虽然我认为将regex-let-form添加到现有let块中将是一个更清晰的解决方案:

(let ((sexp (preceding-sexp))
      (regex-let-form "(let\\*?[ \t]*"))
    ...

答案 3 :(得分:-1)

也许你的例子没有表明真正的问题,你真的想做一些显示替换或字体锁定,如你所说。

但我会回答你的例子以及所提出的问题,关于可维护性与可读性:只需let - 绑定你的正则表达式。与defconst不同,绑定将在附近,并且与绑定变量的出现明显相关。

这通常是人们的行为。同样,你可能还有另一个用例 - 我只是对这个问题作出了狭隘的回应。