4

Suppose I have a short string in C++ and I accidentally delete the double quote that ends it. What Emacs does is highlight the rest of the code as a single very long string, which messes up all the formatting until I put the double quote back in. It also feels a little slow when it's refontifying the whole buffer.

I skimmed through cc-mode.el, but I couldn't find the setting for it or the place where string fontification happens.

Is there a way to tell c++-mode (or font-lock maybe?) that my strings never contain newlines and it should never look beyond the first newline if it finds an unterminated string literal?

  • Do you use any syntax checkers? i.e like flycheck or flymake? They will show you the line with error, so it will be easy to correct. – Ian Mar 5 at 11:37
  • 1
    @Ian Even if I know where the double quote is missing, it still makes the entire buffer after it look like a single long string. That is what I'm trying to avoid. – Kirill Mar 5 at 12:02
  • Are you sure that you want to change this? The system is working as designed, giving you feedback that your code isn't correct. – Tripp Lilley May 4 at 15:28
  • @TrippLilley Yes: unfontifying and then refontifying the entire buffer after the string looks ugly and there is a noticeable UI lag too. Flycheck and lsp will always tell me about syntax errors anyway. Xcode, for example, highlights strings with a missing final quote only up to the next newline, and it looks much better to me that way. – Kirill May 4 at 15:34
  • I'm assuming this involves changing syntax tables as this mode might not do font locking itself. – DoMiNeLa10 May 7 at 16:24
1
+50

The function c-literal-limits, defined in progmodes/cc-engine.el determines how strings and comments are identified in all c-mode variants. It uses these two definitions to do so:

;; String syntax chars, suitable for skip-syntax-(forward|backward).
(defconst c-string-syntax (if (memq 'gen-string-delim c-emacs-features)
                              "\"|"
                            "\""))

;; Regexp matching string limit syntax.
(defconst c-string-limit-regexp (if (memq 'gen-string-delim c-emacs-features)
                                    "\\s\"\\|\\s|"
                                  "\\s\""))

Unfortunately, since this is not a configurable variable, you cannot just reassign it, and have c-mode do what you want it to do. You would have to basically implement "advice" (see: defadvice) for the c-literal-limits function that uses your constants instead. These constants would add an EOL (i.e., "\\s$") to terminate the string expression.

This, of course, is not how the C/C++ language works, though, so I highly recommend not doing this, but the choice is yours, and as you can see, it's not an easy path.

  • 2
    It wasn't until C++0x that C++ had multi-line string literals. C doesn't have them at all AFAIK. – Sam May 8 at 2:52
  • You are right. I guess a better thing would be for Emacs to flag them as an error in non-C++ files. – cyberbisson May 8 at 17:00
  • Multi-line string literals in C++ have a special syntax introduced in C++11, they wouldn't necessarily appear like regular strings to emacs (e.g., R""(string-contents)"". – Kirill May 11 at 16:42
  • 1
    This works, but I don't want to "accept" this answer because it just seems so convoluted to have to advice/edit cc-engine.el just to get this feature. If I understood correctly, this only works for c-mode, which surprised me because I'd thought that identifying string literals was something done by emacs itself and then exposed through functions like syntax-ppss. – Kirill May 15 at 16:52
  • @Kirill "This works, but I don't want to "accept" this answer because it just seems so convoluted to have to advice/edit cc-engine.el just to get this feature" I hear ya. The syntax engine in c-mode is not always flexible because it supports a lot of features, unfortunately... – cyberbisson May 15 at 17:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.