7

I have another syntax highlighting for SQL keywords inside strings (inside quotes) in VIM. It looks like this:

enter image description here

Then in Emacs with PHP-mode, everything between quotes (') will be considered as a string by the font lock:

enter image description here

As you can see, the first example with another font face properties (no cursive keywords) is more clear. The keywords are much easier to distinct.

When I'm looking into my font face properties:

 (font-lock-string-face ((t (:foreground "#536991" :slant italic)))) 

Then I'm wondering how I could tell that there another face inside a font-lock-string-face should be applied, if it matchs the specific keywords.

Any suggestion would be appreciated.

2
  • Again PHP-mode as in emacs.stackexchange.com/questions/19002/…? And do you have the hack from that answer running? You should add a note about the current major mode in the question.
    – Tobias
    Dec 31, 2015 at 14:16
  • @Tobias the StackExchange didn't notified me that I got a reply from you! Very sorry for my belated response then, see the link for my reply. And you're right, I added the PHP-mode. But I believe the solution might be not related to the major mode, since it's targeting only on font faces.
    – ReneFroger
    Dec 31, 2015 at 19:23

1 Answer 1

11

The following elisp snippet should do. The important details are:

  • Strings are handled by syntax highlighting and not by pattern matching (i.e., keyword highlighting). This has very high priority. So one needs to override it explicitly by the value t for the MATCHER flag OVERRIDE (see doc of font-lock-keywords).
  • One cannot use a regexp as keyword MATCHER since one has to check only SQL keywords within strings. The code below provides php-sql-keyword-matcher for that purpose. The test for strings is done via syntax-ppss (see the doc for this function).

Note that I only have a display of class color. So I could not test the other classes. I assume that you have an other display class since strings are displayed in italic face in your example. If you do not get the expected result please customize the face php-sql-keyword-face.

(require 'sql) ;; for sql-keywords
(require 'php-mode) ;; for php-mode-hook

(defvar php-sql-keywords (concat "\\<" (mapconcat 'car sql-mode-ansi-font-lock-keywords "\\|") "\\>")
  "SQL keywords for php-mode stolen from `sql-mode-ansi-font-lock-keywords'.")

(defun php-sql-keyword-matcher (end)
  "Search for SQl keywords within PHP strings."
  (let (pos (case-fold-search t))
    (while (and (setq pos (re-search-forward php-sql-keywords end t))
                (null (nth 3 (syntax-ppss pos)))))
    (when pos (message "Found keyword at %s" pos))
    pos))

(defface php-sql-keyword-face
  '((((class grayscale))  :slant nil :inherit font-lock-string-face)
    (((class color)) :slant italic :inherit font-lock-string-face)
    (t :slant nil :inherit font-lock-string-face))
  "Face to highlight SQL keywords within PHP strings."
  :group 'php-sql)

(defcustom php-sql-keyword-face 'php-sql-keyword-face
  "Face to highlight SQL keywords within PHP strings."
  :type 'face
  :group 'php-sql)

(defun php-add-sql-keyword-matcher ()
  "Hook to add fontification of sql-keywords in strings."
  (font-lock-add-keywords
   nil
   '((php-sql-keyword-matcher 0 php-sql-keyword-face t))
   'append))

(add-hook 'php-mode-hook 'php-add-sql-keyword-matcher)

Note: Please do not only insert images of texts that are needed for the reconstruction of the problem. The ascii text can ease potential helpers the reconstruction of the problem. For the case that someone other has a better solution I insert the ASCII-version of the text here:

$sSql = 'SELECT T05.foo
             T07.bar

         FROM db_pgm_intranet.inttbl_keyuser_proces_keyuser T05

             INNER JOIN db_pgm_intranet.inttbl_keyuser_keyuser T07
             ON    T07.nKkuID = T01.nKpkKeyuserID

             LEFT JOIN db_pgm_intranet.inttbl_keyuser_applicate T07
             ON   T06.nKpaProcesID = T07.nKapID';

And here a picture of the text as it looks like when I load it into emacs with PHP mode:

Picture of the php file with italic keywords in sql strings

With display class color strings are not italic but have a different color. Therefore, I have chosen italic font face for SQL keywords within strings.

The comments indicate some difficulties with this answer. It has been indicated that the solution would not work with the default font set to Consolas. I've just tested it and on my system it also works with Consola font as default:

Highlighting of SQL keywords in php strings with Consolas fonts as default.

In the help for font-lock-add-keywords I found the following text:

For example:

(font-lock-add-keywords 'c-mode
  '(("\\<\\(FIXME\\):" 1 'font-lock-warning-face prepend)
    ("\\<\\(and\\|or\\|not\\)\\>" . 'font-lock-keyword-face)))

adds two fontification patterns for C mode, to fontify 'FIXME:' words, even in comments, and to fontify and, or and not words as keywords.

The first case "FIXME" is the interesting one. Here they use prepend as override flag.

9
  • 1
    Tobias, you tried to help me again. I cannot thank you enough. I studied the documentiation of variable font-lock-keywords (22.6.2 search-based fontification). It seems I need to set the subexp-highlighter override flag to true. But I see you already did with (php-sql-keyword-matcher 0 php-sql-keyword-face t). So I copied you code in a empty Emacs configuration with only PHP-mode on board, evaluated the buffer, then created a new buffer with the ASCII-text that you even reconstructed! Despite your detailed excellent explaination, I see no cursive text or different text, unfortunately.
    – ReneFroger
    Jan 1, 2016 at 19:51
  • Furthermore, when I put my cursor into the string, and call php-sql-keyword-matcher (I have added (interactive) to it)., I get an error, so I assume it's not intented for interactive calls. After evaluating your code and pasted the ASCII-text into scratch buffer with PHP-mode enabled, I see no difference between SQL-keywords and the rest of the strings. If you need a screenshot, of debugging information, I would love to add more information since my Elisp knowledgde is not sufficient yet. I really appreciated your help in my cases, and by the way, best wishes for 2016.
    – ReneFroger
    Jan 1, 2016 at 20:12
  • 1
    The most likely origin of the problem is that jit-ock gives up on some error. jit-lock does not bail out on errors but deactivates the handler that causes the error and goes on with its job. Nevertheless, it leaves an error message in the message buffer. So start a fresh emacs try your stuff and observe very carefully the message buffer. AFAIK you cannot catch these kind of errors via debugger. Stopping jit-lock on error could have wired consequences such as dead lock. I assume it is again some missing function. I will try again with -Q. By the way, best wishes to you too.
    – Tobias
    Jan 1, 2016 at 20:46
  • 1
    I can confirm that the code snippet runs fine with emacs -Q here at my place with X11 interface. I will try again in console mode...
    – Tobias
    Jan 1, 2016 at 20:55
  • which version of Emacs do you use then? I use Emacs 25.50 on Ubuntu, and there is no PHP-mode with M-x php-mode in the empty Emacs configuration. That's why I boarded the PHP-mode with a empty configuration further.
    – ReneFroger
    Jan 1, 2016 at 20:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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