vec
with the vec ;; keyword. (hack-font-lock-xhp (0 'default)) (hack--search-forward-keyword (0 'font-lock-keyword-face)) (hack--search-forward-constant (0 'font-lock-constant-face)) (hack--search-forward-type (1 'font-lock-type-face)) ;; We use font-lock-variable-name-face for consistency with c-mode. (hack--search-forward-user-constant (0 'font-lock-variable-name-face)) ;; $$ is a special variable used with the pipe operator ;; |>. Highlight the entire string, to avoid confusion with $s. (hack--search-forward-dollardollar (0 'font-lock-variable-name-face)) ;; Highlight variables that start with $, e.g. $foo. Don't ;; highlight the $, to make the name easier to read (consistent with php-mode). (hack--search-forward-variable (1 'font-lock-variable-name-face)) (hack--search-forward-built-in-function (1 'font-lock-builtin-face)) (hack--search-forward-function-name 1 font-lock-function-name-face) (hack-font-lock-fallthrough (1 'font-lock-keyword-face t)) (hack-font-lock-unsafe (1 'error t)) (hack-font-lock-unsafe-expr (1 'error t)) (hack-font-lock-fixme (1 'error t)) (hack-font-lock-ignore-error (1 'error t)) ;; TODO: It would be nice to highlight interpolation operators in ;; Str\format or metacharacters in regexp literals too. (hack-font-lock-interpolate (0 font-lock-variable-name-face t)) (hack-font-lock-interpolate-complex (0 font-lock-variable-name-face t)))) (defvar hack-mode-syntax-table (let ((table (make-syntax-table))) ;; Characters that are punctuation, not symbol elements. (modify-syntax-entry ?- "." table) (modify-syntax-entry ?< "." table) (modify-syntax-entry ?> "." table) (modify-syntax-entry ?+ "." table) (modify-syntax-entry ?& "." table) (modify-syntax-entry ?| "." table) (modify-syntax-entry ?= "." table) ;; Treat \ as punctuation, so we can navigate between different ;; parts of a namespace reference. (modify-syntax-entry ?\\ "." table) ;; Strings (modify-syntax-entry ?\" "\"" table) (modify-syntax-entry ?\\ "\\" table) (modify-syntax-entry ?' "\"" table) ;; Comments of the form ;; # This is a single-line comment. ;; Tag these as comment sequence b. (modify-syntax-entry ?# "< b" table) ;; / can start both // and /* style comments. When it's a second ;; character, it's a single line comment, so also tag as comment ;; sequence b. (modify-syntax-entry ?/ ". 124b" table) ;; * is the second character in /* comments, and the first ;; character in the end */. (modify-syntax-entry ?* ". 23" table) ;; Newlines end both # and // comments. Ensure we support both ;; unix and dos style newlines. (modify-syntax-entry ?\n "> b" table) (modify-syntax-entry ?\^m "> b" table) ;; < and > are paired delimiters. (modify-syntax-entry ?< "(>" table) (modify-syntax-entry ?> ")<" table) table)) (defun hack--comment-prefix (s) "Extract the leading '* ' from '* foo'." (when (string-match (rx bol (0+ space) (? "/") "*" (1+ space)) s) (match-string 0 s))) (defun hack--wrap-comment-inner (s) "Given a string of the form: * a very long sentence here... wrap it to: * a very long * sentence here..." (let* ((prefix (hack--comment-prefix s)) (lines (s-lines s)) (stripped-lines (mapcar (lambda (line) (s-chop-prefix prefix line)) lines))) (with-temp-buffer (insert (s-join "\n" stripped-lines)) (goto-char (point-min)) (fill-paragraph) (let* ((wrapped-lines (s-lines (buffer-string))) (prefixed-lines (mapcar (lambda (line) (concat prefix line)) wrapped-lines))) (s-join "\n" prefixed-lines))))) (defun hack--fill-paragraph-star () "Fill paragraph when point is inside a /* comment." (let* ((line-start-pos (line-beginning-position)) (comment-start (nth 8 (syntax-ppss))) (comment-end nil)) ;; Put a property on the text at point, so we can put point back afterwards. (put-text-property (point) (1+ (point)) 'hack-fill-start-pos t) (save-excursion (search-forward "*/") (setq comment-end (point))) (save-excursion (save-restriction ;; Narrow to the comment, to ensure we don't move beyond the end. (narrow-to-region comment-start comment-end) ;; Move over all the non-empty comment lines, considering * to ;; be an empty line. (while (and (not (eobp)) (not (looking-at (rx bol (? "/") (0+ space) (? "*") (0+ space) eol)))) (forward-line)) (if (eobp) ;; Don't add the */ to our wrapped comment. (progn (forward-line -1) (end-of-line)) ;; Exclude the trailing newline. (backward-char)) (let ((contents (buffer-substring line-start-pos (point)))) (delete-region line-start-pos (point)) (insert (hack--wrap-comment-inner contents))))) (while (and (not (eobp)) (not (get-text-property (point) 'hack-fill-start-pos))) (forward-char)) (when (get-text-property (point) 'hack-fill-start-pos) (remove-text-properties (point) (1+ (point)) '(hack-fill-start-pos nil))))) (defun hack-fill-paragraph (&optional _justify) "Fill the paragraph at point." (let* ((ppss (syntax-ppss)) (in-comment-p (nth 4 ppss)) (comment-start (nth 8 ppss)) (comment-end nil) (in-star-comment-p nil)) (when in-comment-p (save-excursion (goto-char comment-start) (when (looking-at (rx "/*")) (setq in-star-comment-p t)))) (if in-star-comment-p (progn (hack--fill-paragraph-star) t) ;; Returning nil means that `fill-paragraph' will run, which is ;; sufficient for // comments. nil))) (defvar hack-xhp-indent-debug-on nil) (defun hack-xhp-indent-debug (&rest args) "Log ARGS if ‘hack-xhp-indent-debug-on’ is set." (if hack-xhp-indent-debug-on (apply 'message args))) (defun hack-xhp-in-code-p () "Return non-nil if point is currently in code, i.e. not in a comment or string." (let* ((ppss (syntax-ppss)) (in-string (nth 3 ppss)) (in-comment (nth 4 ppss))) (and (not in-comment) (not in-string)))) (defun hack-xhp-indent-previous-semi (limit) "Search backward from point for the last semicolon. Return nil if no semicolons were found before we reached position LIMIT. Ignore semicolons in strings and comments." (if (not limit) (setq limit (point-min))) (when (> (point) limit) (let (res (keep-going t)) (save-excursion (while keep-going (setq keep-going nil) (when (search-backward ";" limit t) (if (hack-xhp-in-code-p) (setq keep-going t) ;; semi found, done. (setq res (point))))) res)))) (defun hack-xhp-backward-whitespace () "Move backwards until point is not on whitespace." (catch 'done (while t (when (bobp) (throw 'done nil)) (let ((prev-char (char-after (1- (point)))) (prev-syntax (syntax-after (1- (point))))) (unless (or (eq prev-char ?\n) ;; 0 is the syntax code for whitespace. (eq 0 (car-safe prev-syntax)) ;; Ignore whitespace in comments. (nth 4 (syntax-ppss))) (throw 'done nil))) (backward-char)))) (defun hack-xhp-enclosing-brace-pos () "Return the position of the innermost enclosing brace before point." (nth 1 (syntax-ppss))) (defun hack-xhp-indent-offset () "If point is inside an XHP expression, return the correct indentation amount. Return nil otherwise." (let* ((start-pos (point)) (min-brace (save-excursion ;; get out of anything being typed that might confuse the parsing (beginning-of-line) (hack-xhp-enclosing-brace-pos))) (min (save-excursion (or (hack-xhp-indent-previous-semi min-brace) min-brace ;; skip past (point) min) (re-search-backward hack-xhp-start-regex min t) (hack-xhp-in-code-p)) (setq base-indent ;; decide from this context if indentation should ;; be initially adjusted. (+ ;; start with the indentation at this elt (current-indentation) ;; at the matched xhp element, figure out if the ;; indentation should be modified ;; TODO(abrady) too lazy to parse forward properly, these ;; work fine for now. (cond ;; CASE 1: matched elt is closed or self-closing e.g.