2

I want to type everything in lowercase, but have a command to turn the whole buffer into uppercase except for quoted strings.

What is the command to tell emacs to ignore quoted strings?

  • 2
    You need to be more specific when you say "quoted strings". Different programming languages and writing traditions have different concepts of what constitutes a quoted string. For example, single quote may be used as a paired delimiter (JavaScript, Python, Bash etc.) or not (Lisps, Haskell etc.) – wvxvw Oct 12 '15 at 6:47
  • If something doesn't exist out of the box for this (you don't get a useful answer), you can probably code this by searching for a non-string and selecting that text, then using upcase-region (and repeat througout the buffer). – Drew Oct 12 '15 at 15:54
2

Major modes have a syntax table that can define how strings are delimited. Is it a smart or a dumb idea to leverage that? Let's assume smart....

Although I'm not confident of the code quality, here is a command that will work even in a major mode (like text-mode) that doesn't define strings in its syntax table. The command will temporarily change the mode's syntax table to say that single and double quotes are string delimiters. If the major mode does define additional string delimiters, it will use those, too.

(defun my/upcase-non-strings ()
  "Uppercase all except strings.

Ignores both single- and double-quoted strings. If the buffer's
current major mode defines other things to be strings, they will
be ignored, too."
  (interactive)
  (let* ((old-syntax-table (syntax-table))
         (new-syntax-table (make-syntax-table old-syntax-table)))
    (modify-syntax-entry ?\" "\"   " new-syntax-table)
    (modify-syntax-entry ?\' "\"   " new-syntax-table)
    (with-syntax-table new-syntax-table
      (save-excursion
        (goto-char (point-min))
        (while (< (point) (point-max))
          (while (and (< (point) (point-max))
                      (nth 3 (syntax-ppss (point)))) ;in string
            (goto-char (1+ (point))))
          (let ((start (point)))
            (while (and (< (point) (point-max))
                        (not (nth 3 (syntax-ppss (point))))) ;not in string
              (goto-char (1+ (point))))
            (upcase-region start (point))))))))

Why my caveat about code quality? Calling syntax-ppss repeatedly on every character feels like it might be bad. Possibly there's a way to use parse-partial-sexp, more efficiently, but I didn't immediately see how. I'm still going to look at that, but meanwhile I wanted to post this answer in case it was "good enough" for your purposes.

Note: Although you could use in-string-p, that seems to be deprecated starting in Emacs 25.1, with a message saying to use (nth 3 (syntax-ppss pos)) instead. So above, I did.


Update

I spent more time on this and figured out how to use parse-partial-sexp. Although I don't know how much more efficient this is, it's certainly more concise:

(defun my/upcase-non-strings ()
  "Uppercase all except strings.

Ignores both single- and double-quoted strings. If the buffer's
current major mode defines other things to be strings -- or
comments! -- they will be ignored, too."
  (interactive)
  (let* ((old-syntax-table (syntax-table))
         (new-syntax-table (make-syntax-table old-syntax-table)))
    (modify-syntax-entry ?\" "\"   " new-syntax-table)
    (modify-syntax-entry ?\' "\"   " new-syntax-table)
    (with-syntax-table new-syntax-table
      (save-excursion
        (goto-char (point-min))
        (while (< (point) (point-max))
          (let ((beg (point)))
            ;; Supplying 'syntax-table for the optional STOP-COMMENT
            ;; arg causes the parse to stop at the beginning or end
            ;; of a comment or string.
            (parse-partial-sexp (point) (point-max) nil nil nil 'syntax-table)
            (upcase-region beg (point))
            (parse-partial-sexp (point) (point-max) nil nil nil 'syntax-table)))))))

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.