3

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

我们来看看下面的函数。它的作用并不重要,重要的是它使用了两倍的字符串"(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++-mode 完成了,但还没有为 emacs-lisp-mode 完成。

然后它只剩下将两者连接起来。不幸的是,我没有足够的font-lock内脏来做这件事,但也许其他人会做?还是已经有一个包可以做到这一点?

4

4 回答 4

1

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

于 2013-10-20T18:10:23.963 回答
1

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

(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将变量标记为特殊且有风险,但仅此而已。

于 2013-08-20T07:41:55.253 回答
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]*"))
    ...
于 2013-07-17T22:50:01.247 回答
-1

也许您的示例并不能说明真正的问题,并且您确实想要进行一些显示替换或字体锁定,如您所说。

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

这通常是人们所做的。同样,您可能已经想到了另一个用例 --- 我只是对提出的问题做出狭隘的回应。

于 2013-08-10T22:27:20.800 回答