button-lock icon indicating copy to clipboard operation
button-lock copied to clipboard

Error message

Open llcc opened this issue 10 years ago • 2 comments

Hi @rolandwalker

Thanks for your good package. I have a problem by setting a button to make LaTeX package in \usepackage{...} clickable with the following code:

(make-variable-buffer-local
 (defvar *texdoc-buttons* '() "list of texdoc buttons"))

(require 'rx)

(defun* texdocs ()
  (interactive)
  (save-excursion
    (let ((case-fold-search t))
      (goto-char (point-min))
      (while (re-search-forward "\\\\usepackage.*{\\(.+\\)}" nil t)
    (let* ((package1 (match-string 1)))
    (add-to-list '*texdoc-buttons*
             (button-lock-set-button
              (rx word-start (eval package1) word-end)
              (lambda ()
            (interactive)
            (call-process "texdoc" nil 0 nil "--view" (match-string 1))))))))))

But it give me a Wrong type argument: stringp, nil error, do you know what the wrong with this code?

llcc avatar Aug 11 '15 03:08 llcc

Hi!

I'm not sure where you are getting the error Wrong type argument: stringp, nil. The best way to resolve that is to use Edebug, by placing the point at the end of the definition of texdocs and pressing C-u C-M-x, as described at http://www.gnu.org/software/emacs/manual/html_node/elisp/Using-Edebug.html . After that, invoking texdocs will allow you to step through the function.

However, I can give a few comments on the above code:

  • rx is a macro, evaluated at the time that the defun texdocs is compiled. So, the variable package1 within the macro cannot hold different values at different iterations of the loop. There is an ordinary function rx-to-string which will be evaluated at runtime if you use this:

    (rx-to-string `(and word-start ,package1 word-end))
    
  • The .* in the usepackage regular expression matches anything, and could run past where expected. If we are trying to handle eg \usepackage[utf8]{packagename} then perhaps this expression is better

    "\\\\usepackage[^ {}]*?{\\(.+\\)}"
    
  • It is not necessary to create a separate button for each usepackage. When the function associated with a button is called, that function can see the position of the point. So, the bracketed string can be discovered at invocation time, using a single button definition:

    (require 'thingatpt)
    (make-variable-buffer-local
     (defvar *texdoc-buttons* '() "list of texdoc buttons"))
    
    (defun* texdocs ()
      (interactive)
      (add-to-list '*texdoc-buttons*
                   (button-lock-set-button
                    "\\\\usepackage[^ {}]*?{\\(.+\\)}"
                    #'(lambda ()
                        (interactive)
                        (let ((package-name (thing-at-point 'word)))
                          (message "running texdoc on %s..." package-name)
                          (call-process "texdoc" nil 0 nil "--view" package-name)))
                    :grouping 1)))
    
  • texdocs does not need to be an interactive command. The same logic could be applied automatically for all TeX buffers via tex-mode-hook:

    (require 'thingatpt)
    (make-variable-buffer-local
     (defvar *texdoc-buttons* '() "list of texdoc buttons"))
    
    (add-hook 'tex-mode-hook
              #'(lambda ()
                  (unless (and (boundp '*texdoc-buttons*)
                               *texdoc-buttons*)
                    (add-to-list '*texdoc-buttons*
                                 (button-lock-set-button
                                  "\\\\usepackage[^ {}]*?{\\(.+\\)}"
                                  #'(lambda ()
                                      (interactive)
                                      (let ((package-name (thing-at-point 'word)))
                                        (message "running texdoc on %s..." package-name)
                                        (call-process "texdoc" nil 0 nil "--view" package-name)))
                                  :grouping 1)))))
    

rolandwalker avatar Aug 11 '15 14:08 rolandwalker

@rolandwalker Thanks for your elaborated explanation, I really learned about something from your reply. Your code works like a charm.

Hope you enjoy your every days.

llcc avatar Aug 13 '15 15:08 llcc