Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docstrings in protocol methods #1

Closed
raxod502 opened this issue Jul 26, 2016 · 4 comments
Closed

Docstrings in protocol methods #1

raxod502 opened this issue Jul 26, 2016 · 4 comments

Comments

@raxod502
Copy link
Member

raxod502 commented Jul 26, 2016

Consider the following protocol definition:

(defprotocol Foo
  "Docstring. This one is multiline. It has quite a lot of useless
  information that is only meant to fill extra space."
  (example-method
    [this]
    "Docstring. This one is multiline. It has quite a lot of useless
information that is only meant to fill extra space."))

The first docstring (the docstring for the entire protocol) is colored in dark green because it is recognized by clojure-mode as a docstring. The second one, however, is not.

Additionally, pressing TAB does not indent the second docstring correctly, i.e. as follows:

(defprotocol Foo
  "Docstring. This one is multiline. It has quite a lot of useless
  information that is only meant to fill extra space."
  (example-method
    [this]
    "Docstring. This one is multiline. It has quite a lot of useless
  information that is only meant to fill extra space."))

This is likely because clojure-mode does not recognize it as a docstring.

The relevant code to modify is in clojure-mode.el, and is as follows:

(defun clojure-font-lock-syntactic-face-function (state)
  "Find and highlight text with a Clojure-friendly syntax table.

This function is passed to `font-lock-syntactic-face-function',
which is called with a single parameter, STATE (which is, in
turn, returned by `parse-partial-sexp' at the beginning of the
highlighted region)."
  (if (nth 3 state)
      ;; This might be a (doc)string or a |...| symbol.
      (let ((startpos (nth 8 state)))
        (if (eq (char-after startpos) ?|)
            ;; This is not a string, but a |...| symbol.
            nil
          (let* ((listbeg (nth 1 state))
                 (firstsym (and listbeg
                                (save-excursion
                                  (goto-char listbeg)
                                  (and (looking-at "([ \t\n]*\\(\\(\\sw\\|\\s_\\)+\\)")
                                       (match-string 1)))))
                 (docelt (and firstsym
                              (function-get (intern-soft firstsym)
                                            lisp-doc-string-elt-property))))
            (if (and docelt
                     ;; It's a string in a form that can have a docstring.
                     ;; Check whether it's in docstring position.
                     (save-excursion
                       (when (functionp docelt)
                         (goto-char (match-end 1))
                         (setq docelt (funcall docelt)))
                       (goto-char listbeg)
                       (forward-char 1)
                       (condition-case nil
                           (while (and (> docelt 0) (< (point) startpos)
                                       (progn (forward-sexp 1) t))
                             ;; ignore metadata and type hints
                             (unless (looking-at "[ \n\t]*\\(\\^[A-Z:].+\\|\\^?{.+\\)")
                               (setq docelt (1- docelt))))
                         (error nil))
                       (and (zerop docelt) (<= (point) startpos)
                            (progn (forward-comment (point-max)) t)
                            (= (point) (nth 8 state)))))
                font-lock-doc-face
              font-lock-string-face))))
    font-lock-comment-face))

I do not envy whoever tries to fix this.

@raxod502
Copy link
Member Author

Sometimes I extend clojure.core macros in nonstandard ways in order to add docstring functionality (e.g. for defonce and defrecord). It would be nice if there were an extensible way to add docstring recognition to arbitrary forms.

@raxod502 raxod502 added the emacs label Jul 28, 2016
@raxod502
Copy link
Member Author

raxod502 commented Aug 4, 2016

This could be accomplished by marking all strings as docstrings, which would eliminate the issue of some docstrings being nonstandard additions. Then we would have electric indentation in all multiline strings in Clojure. Since we don't really have very many multiline strings that aren't docstrings in Clojure, this would probably be a reasonable solution to the problem.

@raxod502 raxod502 self-assigned this Aug 4, 2016
@raxod502
Copy link
Member Author

raxod502 commented Aug 7, 2016

I'm just going to leave this code here:

(defsubst clojure-in-docstring-p ()
  "Check whether point is in a docstring."
  (eq (get-text-property (point) 'face) 'font-lock-doc-face))

Yes, it actually determines docstrings according to the font color.

@raxod502
Copy link
Member Author

raxod502 commented Aug 7, 2016

Resolved in 0077229. Sort of -- the docstrings in protocol methods now have electric indentation, but they still aren't colored as docstrings.

But the docstrings I've hacked on to non-docstring-allowing functions are never going to get colored as docstrings, so this doesn't really bother me.

Since the remaining issue is upstream, I've opened an issue on clojure-mode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

1 participant