This post covers the following sections from my init.
- Web Mode
Preamble
Emacs is old school. You're either new to it - which means you wouldn't be here unless it was your type of thing - or you know what you're looking for. In either case, search 'Emacs' in tags or search on this site. Then read the posts y date from oldest to newest.
In the last emacs post I covered lines 2995 - 3057. This post covers lines 3129 - 3335. In the gap between the lines there is code posted at Windows Program Launcher. I include the lines for anyone that wants to patch together the entire init from start to finish. The lines won't always match up because I take stuff out when I'm in the init.
Web Mode for emacs enables things like folding, easy movement between attributes, sections, tags; easy insertion of code snippets, and more.
I use it with other modes, like emmet, helm-emmet, company, and yasnippet, so I don't use all the functionality that comes with web-mode, but it's still hugely useful.
Some things I do a lot are toggle between Web-Mode, HTML Mode, PHP mode and JS-Mode (for html files with script tags in them). Actually, once I lined up the snippet engine for web-mode and html mode, I don't use html (sgml) modes much.
The main things you want to ensure are easy movement (a short-cut scheme that lines up with your emacs movement shortcuts), excellent snippet, company, and emmet integration, and easy expansion/copy/paste etc.
I don't have time to explain much (these posts take me about thirty-minutes (once I include the screen shots), but here's some configuration
Web Mode
(use-package web-mode
:commands (web-mode)
:mode (("\\.html" . web-mode)
("\\.htm" . web-mode)
; ("\\.tsx$" . web-mode)
; ("\\.mustache\\'" . web-mode)
; ("\\.phtml\\'" . web-mode)
; ("\\.as[cp]x\\'" . web-mode)
; ("\\.erb\\'" . web-mode)
("\\.sgml\\'" . web-mode))
:config
(setq web-mode-markup-indent-offset 2)
(setq web-mode-css-indent-offset 2)
(setq web-mode-code-indent-offset 2)
(setq web-mode-comment-style 2)
(setq web-mode-enable-auto-indentation nil)
(setq web-mode-enable-css-colorization t)
(setq web-mode-enable-block-face t)
(setq web-mode-enable-comment-keywords t)
(setq web-mode-enable-heredoc-fontification t)
;;lots of attribute styles available at web-mode.org
(set-face-attribute 'web-mode-css-at-rule-face nil :foreground "Pink3")
;Part face: can be used to set parts background and default foreground
;(see web-mode-script-face and web-mode-style-face which inheritate fromweb-mode-part-face)
(setq web-mode-enable-part-face t)
;; make these variables local
(make-local-variable 'web-mode-code-indent-offset)
(make-local-variable 'web-mode-markup-indent-offset)
(make-local-variable 'web-mode-css-indent-offset)
(setq web-mode-enable-html-entities-fontification t
web-mode-auto-close-style 2)
;start use smartparens to complete tags not webmode
(defun +web-is-auto-close-style-3 (_id action _context)
(and (eq action 'insert)
(eq web-mode-auto-close-style 3)))
;initialize smartparens mode to ensure sp-local-pair defined
(smartparens-mode t)
(sp-local-pair 'web-mode "<" nil :unless '(:add +web-is-auto-close-style-3));end with eval after load
;; let smartparens handle these
(setq web-mode-enable-auto-quoting nil
web-mode-enable-auto-pairing t)
(setq web-mode-engine "php")
;set some auto-pairs
(setq web-mode-extra-auto-pairs
'(("erb" . (("beg" "end")))
("php" . (("beg" "end")
("beg" "end")))
));end autopairing
(setq web-mode-engines-alist '(
("php" . "\\.html\\'")
("php" . "\\.php\\'")))
;; 1. Remove web-mode auto pairs whose end pair starts with a latter
;; (truncated autopairs like <?p and hp ?>). Smartparens handles these
;; better.
;; 2. Strips out extra closing pairs to prevent redundant characters
;; inserted by smartparens.
(dolist (alist web-mode-engines-auto-pairs)
(setcdr alist
(cl-loop for pair in (cdr alist)
unless (string-match-p "^[a-z-]" (cdr pair))
collect (cons (car pair)
(string-trim-right (cdr pair) "\\(?:>\\|]\\|}\\)+")))))
(setf (alist-get nil web-mode-engines-auto-pairs) nil)
;end use smartparens not webmode to complete autopairs
;; highlight matching tag
(setq web-mode-enable-current-element-highlight t)
(setq web-mode-enable-current-column-highlight t)
(setq html2text t)
;For <style> parts
(setq web-mode-style-padding 1)
;For <script> parts
(setq web-mode-script-padding 1)
;For multi-line blocks
(setq web-mode-block-padding 0)
;; colorize colors in buffers
(setq web-mode-enable-css-colorization t)
(use-package company-web
:commands (web-mode company-web-html)
:load-path company-web-p
:config
;(unless (assoc "Bootstrap" web-completion-data-sources)
;; (setq web-completion-data-sources
;; (cons (cons "Bootstrap" "/path/to/complete/data")
;; web-completion-data-sources)))
(add-to-list 'load-path company-web-completion-data-p)
;(describe-variable 'company-web-completion-data-p)
(require 'company)
(require 'company-web)
(require 'company-web-html)
);end company-web
;etags
(setq tags-table-list
'("~/.emacs.d/ctags2019"))
(setq company-etags-everywhere t)
(setq company-etags-ignore-case t)
;company bootstrap
(use-package company-bootstrap
:load-path company-bootstrap-p
:config
(require 'company-bootstrap)
);end ac-html-bootstrap
;require company-css
(require 'company-css)
(defun company-web-mode-hook ()
(set (make-local-variable 'company-backends) '(company-web-html company-bootstrap company-etags company-yasnippet company-css company-dabbrev-code company-dabbrev )))
;hook
:hook
(web-mode . (lambda ()
(progn
(highlight-indent-guides-mode -1)
(emmet-mode 1)
(company-mode 1)
(company-web-mode-hook))));end hook
(web-mode . (lambda ()
;; Make `emmet-expand-yas' not conflict with yas/mode
(setq emmet-preview-default t)
(emmet-mode)
));end hook
:bind (:map web-mode-map(
("<f4>" . php-mode)
("C-c C-v" . buffer-to-browser)
("C-t" . company-complete)
("C-v" . company-web-html)
("C-h" . helm-emmet)
("C-c C-p" . web-mode-element-beginning)
("C-c C-n" . web-mode-element-end)
("C-c C-c" . web-mode-element-content-select)
("TAB" . web-mode-fold-or-unfold)
("C-c C-i" . web-mode-element-child-fold-or-unfold)
("C-c C-s" . yas/insert-snippet)
))
);end use package web-mode
Notes:
You can see there's a lot of set up for buffer appearances. You're not going to need to do as much set up with more modern text-editors; however, emacs is so customizable it's absolutely great if you go the extra mile.
There's also of course associations and enabling web mode to handle php code format. You can see also I've included company-web, company-css, and company-bootstrap, so you can find the snippets you want in the auto-completion drop-down. I give company-mode a hard time, but it actually can be useful to set this stuff up, especially when you can't remember css attribute options.
There's also this bind section (of the use-package) implementation, which sets up short-cuts for getting around and inserting stuff in web-mode, though I usually use the hydra that will come below.
:bind (:map web-mode-map(
("<f4>" . php-mode)
("C-c C-v" . buffer-to-browser)
("C-t" . company-complete)
("C-v" . company-web-html)
("C-h" . helm-emmet)
("C-c C-p" . web-mode-element-beginning)
("C-c C-n" . web-mode-element-end)
("C-c C-c" . web-mode-element-content-select)
("TAB" . web-mode-fold-or-unfold)
("C-c C-i" . web-mode-element-child-fold-or-unfold)
("C-c C-s" . yas/insert-snippet)
))
A couple of quick functions for getting around that go in the hydra:
(defun skip-to-next-blank-line ()
(interactive)
(let ((inhibit-changing-match-data t))
(skip-syntax-forward " >")
(unless (search-forward-regexp "^\\s *$" nil t)
(goto-char (point-max)))))
(defun skip-to-previous-blank-line ()
(interactive)
(let ((inhibit-changing-match-data t))
(skip-syntax-backward " >")
(unless (search-backward-regexp "^\\s *$" nil t)
(goto-char (point-min)))))
; web-beautify
(add-to-list 'load-path "c:/emacs/emax/elpa/web-beautify-20161115.2247/")
(require 'web-beautify)
The Web Mode Hydra:
;web-mode hydra
(defvar web-mode-title (with-octicon "globe" "Web Mode Control"))
;generate hydra
(pretty-hydra-define Web-Mode (:title web-mode-title :quit-key "q" :color blue )
("Mode"
(
("1" beginning-of-buffer "Go To Top Of Page")
("0" end-of-buffer "Go To Bottom Of Page")
("n" web-mode-element-end "Go Element End")
("p" web-mode-element-beginning "Go Element Beginning")
("F" web-mode-element-children-fold-or-unfold "Fold/Unfold Element Children")
("f" web-mode-fold-or-unfold "Fold/Unfold")
("&" web-mode-whitespaces-show "Toggle Show Whitespace" :toggle t)
("s" web-mode-element-content-select "Select Content")
("k" web-mode-element-clone "Clone Element" :color red)
);end mode
"Action"
(
("r" web-mode-element-wrap "Wrap Element In Tag" )
("m" web-mode-mark-and-expand "Mark/Expand Region" :color red )
("E" web-mode-dom-errors-show "Show Errors" )
("N" web-mode-dom-normalize "Normalize HTML" )
("B" web-beautify-html "Beautify HTML")
; ("I" highlight-indent-guides-mode "Show Indent Guides" :toggle t )
);end action
"Other"
(
("i" yas-insert-snippet "Insert Snippet" )
("e" helm-emmet "Insert Emmet Snippet")
("T" company-try-hard "Cycle Completion Backends")
("t" indent-for-tab-command "Style Html Region Indent")
("c" Css-Mode/body "Css-Mode Interface" :color blue)
( "R" Javascripts/body "Javascript Interface" :color blue)
( "w" Web-Development/body "Web Dev Interface" :color blue)
("h" hydra-helm/body "Return To Helm" :color blue )
("<SPC>" nil "Quit" :color blue)
);end other
);end hydra body
);end pretty-hydra-web-development
(bind-key "<C-m> v" 'Web-Mode/body)
Notes:
The hydra is pretty self explanatory. You've got some toggles for folding page sections, some jumps for getting aroudn the page, content selection (for grabbing stuff between element tags), some tag wrap functions, expansions, and beautify/normalize for structuring your code after you write it. Then there's some snippet inserts (though I use always the yasnippet hydra), and links to other hydras, like the javascript hydra, and css hydra, which I use a lot.
Here's a screen shot.