Emacs for Windows中的覆盖层/工具提示是否正常工作?

9

我正在Windows上使用emacs v22.2.1,使用Flymake检查C#代码。

Flymake对我来说一直很有效。对于那些不了解的人,您可以阅读有关flymake的概述,但简单来说,flymake会在后台重复构建您当前正在工作的源文件,以进行语法检查。然后它会在当前缓冲区中突出显示编译器警告和错误。

最初Flymake在C#上无法工作,但是我已经“修补”了它,现在它非常好用。如果您在emacs中编辑C#,我强烈建议使用flymake。

我唯一遇到的问题是UI。Flymake很好地突出显示了错误和警告,然后插入了带有完整错误或警告文本的“覆盖层”,如果我将鼠标指针悬停在代码中突出显示的行上,则会弹出覆盖层工具提示。

alt text

但是正如您所看到的,覆盖工具提示被剪裁了,且未正确显示。
Flymake似乎做得没问题,出问题的是覆盖部分,并且覆盖似乎也做得没问题。显示不正确的是工具提示。
在Windows版emacs中,覆盖工具提示是否正常工作?
我应该在哪里查找修复此问题?

经过一些研究,我发现使用(tooltip-show really-long-string)可以展示效果。

这与覆盖层或flymake无关。


看起来像是一个 bug,你可能想要执行 M-x report-emacs-bug - Trey Jackson
阅读了更多相关内容后,我想真正的问题不在于覆盖层,而是工具提示。 - Cheeso
单行工具提示对我来说看起来很正常(例如,在缓冲区模式下悬停在缓冲区上)。你的是多行的,我怀疑这就是它开始出问题的地方。 - Bahbar
1
是的,我不知道它是否真的是多行的,还是只是一个非常长的错误消息。但你说得对,多行工具提示不起作用。我通过使用带有嵌入式\n的字符串运行tooltip-show来看到这一点。 - Cheeso
有人建议说在 Windows 上的 Emacs 中,这个 bug 在 v23.x 版本中已经修复了。还有其他人可以确认吗? - Cheeso
Emacs开发人员确认这是一个错误(#5908),并且在emacs v23中仍然存在。此外,他们说调整字体也可以解决问题。 - Cheeso
2个回答

8
我通过在tooltip-show上使用defadvice解决了这个问题。
;; Reforms a single-line string ARG to a multi-line string with a max
;; of LIMIT chars on a line.
;;
;; This is intended to solve a problem with the display of tooltip text
;; in emacs on Win32 - which is that the tooltip is extended to be very very
;; long, and the final line is clipped.
;;
;; The solution is to split the text into multiple lines, and to add a
;; trailing newline to trick the tooltip logic into doing the right thing.
;;
(defun cheeso-reform-string (limit arg)
  (let ((orig arg) (modified "") (curline "") word
        (words (split-string arg " ")))
    (while words
      (progn
        (setq curline "")
        (while (and words (< (length curline) limit))
          (progn
            (setq word (car words))
            (setq words (cdr words))
            (setq curline (concat curline " " word))))
        (setq modified (concat modified curline "\n"))))
    (setq modified (concat modified " \n")))
  )

(defadvice tooltip-show (before
                         flymake-csharp-fixup-tooltip
                         (arg &optional use-echo-area)
                         activate compile)
  (progn
    (if (and (not use-echo-area)
             (eq major-mode 'csharp-mode))
        (let ((orig (ad-get-arg 0)))
          (ad-set-arg 0 (cheeso-reform-string 72 orig))
          ))))

result:

alt text


0

当我在调整这个flymake的东西时,真正的目标是让一个“快速修复”选项菜单在flymake显示错误时弹出。如果你点击ALT-Shift-F10,Visual Studio就会做到这一点。

而且,在一些基本场景中,我已经让它工作了。 以下是用户体验:

步骤1:编写代码时出现未解决的类型引用问题 - 在这种情况下,是Stream。Flymake会标记出问题,如下所示:

alt text

步骤2:通过(flymake-display-err-menu-for-current-line)弹出flymake错误菜单

alt text

步骤3:选择菜单项,快速修复将自动应用。

alt text


我安排提供了一些特殊情况下的“快速修复”选项:

  • 错误 CS0246:找不到类型或命名空间“xxxx”
  • 错误 CS1002:需要分号
  • 错误 CS0103:当前上下文中不存在名称“identifier”。

诀窍是建议。这次是在flymake-make-emacs-menu函数上。 flymake中的该函数准备传递给x-popup-menu的数据结构。建议(“after”建议)解析错误列表,查找已知的错误代码,如果找到,则“猴子补丁”弹出菜单,插入修复错误的选项。

;; The flymake-make-emacs-menu function prepares the menu for display in
;; x-popup-menu. But the menu from flymake is really just a static list
;; of errors.  Clicking on any of the items, does nothing. This advice
;; re-jiggers the menu structure to add dynamic actions into the menu,
;; for some error cases.  For example, with an unrecognized type error
;; (CS0246), this fn injects a submenu item that when clicked, will
;; insert a using statement into the top of the file. Other errors are
;; also handled.
;;
;; This won't work generally.  It required some changes to flymake.el,
;; so that flymake-goto-next-error would go to the line AND column.  The
;; original flymake only goes to the line, not the column.  Therefore,
;; quickfixes like inserting a semicolon or a namespace in front of a
;; typename, won't work because the position is off.
;;
(defadvice flymake-make-emacs-menu (after
                                    flymake-csharp-offer-quickfix-menu
                                    ()
                                    activate compile)
  (let* ((menu ad-return-value)
         (title (car menu))
         (items (cadr menu))
         action
         new-items
         )

    (setq new-items (mapcar
                     '(lambda (x)
                        (let ((msg (car x)) missing-type namespace m2 m3)
                          (cond ((or (string-match "error CS0246:" msg)
                                     (string-match "error CS0103:" msg))

                                 (progn
                                   (string-match "^\\(.+'\\([^']+\\)'[^(]+\\)" msg)
                                   (setq missing-type (substring msg
                                                                 (match-beginning 2)
                                                                 (match-end 2)))

                                   ;; trim the message to get rid of the (did you forget to ...?)
                                   (setq msg
                                         (substring msg
                                                    (match-beginning 1)
                                                    (match-end 1)))
                                   (setq namespace (csharp-get-namespace-for-type missing-type))
                                   (if namespace
                                       ;; the namespace was found
                                       (progn
                                         (setq m2 (concat "insert   using " namespace ";"))
                                         (setq m3 (concat namespace "." missing-type))
                                         (list msg
                                               (list m2 'csharp-insert-using-clause-for-type missing-type)
                                               (list m3 'csharp-insert-fully-qualified-type namespace)
                                               (list "resolve this type reference manually")))
                                     ;; couldn't find the namespace; maybe it's just a typo
                                     (list msg
                                           (list "resolve this type reference manually")))))

                                ;; missing semicolon
                                ((string-match "error CS1002:" msg)
                                 (progn
                                     (list msg
                                           (list "insert ; " 'insert ";"))
                                   ))

                                ;; all other cases
                                (t
                                 ;; no quick fixes for this error
                                 (list msg
                                       (list "resolve this error manually"))))))
                     (cdr items)))

    ;; If there's only one menu item, it sometimes won't display
    ;; properly.  The main error message is hidden, and the submenu
    ;; items become the menu items. I don't know why.  Appending a list
    ;; of ("" nil) to the end, insures that the menu will display
    ;; properly.
    (setq new-items (append new-items (list (list "" nil))))

    ;; finally, set the return value
    (setq ad-return-value (cons title new-items))

    ;; (setq ad-return-value (list title
    ;;                             (list "item1" (list "choice 1.A" 1) (list "choice 1.B" 2))
    ;;                             (list "item2" (list "choice 2.A" 3) (list "choice 2.B" 4))
    ;;                             (list "item3")
    ;;                             ))

    ))

“插入 using” 修复还依赖于查找功能,它能够将短类型名称(例如 Stream)解析为完全限定的类型名称(例如 System.IO.Stream)。这是一个独立的问题。

如果用户选择了菜单项来应用快速修复,则会运行一个函数来插入一个新的 “using” 子句:

(defun csharp-insert-using-clause (namespace)
  "inserts a new using clause, for the given namespace"
  (interactive "sInsert using clause; Namespace: ")
  (save-excursion
    (let ((beginning-of-last-using (re-search-backward "^[ \t]*using [^ ]+;")))
      (end-of-line)
      (newline)
      (insert (concat "using " namespace ";"))
    )
  )
)

我认为这可以扩展以处理其他类型错误的快速修复。但我不知道那些易修复的错误可能是什么。如果有人有任何想法或需要帮助,请告诉我。


1
请务必将Lisp代码格式化后再分享,单独一行的尾括号会分散阅读注意力,使Lisp代码更难以阅读。 - Justin Smith
很有趣,这让我更容易阅读。Lisp真的有一个标准格式吗? - Cheeso

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接