├── LICENSE
├── README.md
├── demo.gif
└── htmlz.el
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2020 Zeke Medley
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are
5 | met:
6 |
7 | 1. Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright
11 | notice, this list of conditions and the following disclaimer in the
12 | documentation and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # htmlz-mode
2 |
3 | 
4 |
5 | ```
6 | M-x htmlz-mode
7 | ```
8 |
9 | This is a small, dead-simple, Emacs minor mode that shows a live
10 | preview of a html document as you work on it. This is inspired by the
11 | live preview option for the Brackets text editor.
12 |
13 | ## Usage
14 |
15 | Download the emacs lisp file and move it somewhere that your Emacs
16 | will see and evaluate it on startup. Then, run `M-x htmlz-mode` while
17 | editing an html file to open a live preview in your default browser.
18 |
19 | ## Why
20 |
21 | I made this because I occasionally find myself in the position of
22 | editing some html and wanting to see a simple live preview of it as I
23 | work. If you do this sort of thing seriously, I'd imagine that there
24 | are much better ways to manage this, but as a non web developer who
25 | occasionally needs to write some html I've found this to be quite
26 | pleasant.
27 |
28 | ## How it works
29 |
30 | This is my first Emacs Lisp program ever so it's likely to be less
31 | than ideal in many ways. I'd love feedback.
32 |
33 | In a nutshell, htmlz-mode works like this:
34 |
35 | 1. Create a temporary html file.
36 | 2. Start a websocket server in Emacs.
37 | 3. Place some Javascript in that file that opens a websocket
38 | connection with Emacs.
39 | 4. Open the temporary file in the default browser.
40 | 5. When the buffer contents change send the new buffer contents over
41 | the websocket connection from Emacs.
42 | 6. When a new websocket message is received in the browser, update the
43 | page contents with that message.
44 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xekez/htmlz-mode/013464fc7fc69d52519baf9ba40e20a0c3a031d5/demo.gif
--------------------------------------------------------------------------------
/htmlz.el:
--------------------------------------------------------------------------------
1 | ;;; htmlz --- Simple real-time Emacs html preview
2 |
3 | ;; Copyright (C) 2020 Zeke Medley
4 |
5 | ;; Author: Zeke Medley
6 | ;; Keywords: html
7 | ;; Version: 0.1
8 | ;; URL: https://github.com/ZekeMedley/htmlz
9 |
10 | ;;; Commentary:
11 | ;; htmlz-mode is an Emacs mode that gives a live preview while you
12 | ;; edit html. There are other programs that do this and they are
13 | ;; reasonably good I'm sure, but they all seem a little more
14 | ;; complicated than I'd actually like. This doesn't have any
15 | ;; shortcuts or really add anything other than a live preview that
16 | ;; starts if you run M-x htmlz-mode from a buffer.
17 |
18 | ;;
19 | ;;; Code:
20 |
21 | (defun require-package (package)
22 | "Install given PACKAGE if it was not installed before."
23 | (if (package-installed-p package)
24 | t
25 | (progn
26 | (unless (assoc package package-archive-contents)
27 | (package-refresh-contents))
28 | (package-install package))))
29 |
30 | (defun htmlz-init-dependencies ()
31 | "Initialize htmlz dependencies."
32 | (require-package 'websocket)
33 | (require 'package)
34 | (require 'browse-url)
35 | (require 'websocket))
36 |
37 | (defvar htmlz-opened-websocket nil
38 | "The currently open websocket.")
39 | (defvar htmlz-the-server nil
40 | "The current websocket server. Created after the client opens a websocket connection with us.")
41 |
42 | (defun htmlz-get-current-extension ()
43 | "Gets the file extension for the current buffer."
44 | (car (reverse (split-string (buffer-file-name) "\\."))))
45 |
46 | (defun htmlz-get-current-dir ()
47 | "Gets the directory for the current buffer."
48 | (file-name-directory (buffer-file-name)))
49 |
50 | (defun htmlz-get-filename ()
51 | "Gets the filename for the current buffer."
52 | (concat (htmlz-get-current-dir) "~htmlz-tmp." (htmlz-get-current-extension)))
53 |
54 | (defun htmlz-init-file ()
55 | "Create a file for htmlz to load."
56 | (write-region "
57 | "
67 | nil (htmlz-get-filename)
68 | nil 'quiet))
69 |
70 | (defun htmlz-open-file ()
71 | "Opens the htmlz file in the default browser."
72 | (browse-url (htmlz-get-filename)))
73 |
74 | (defun htmlz-init-server ()
75 | "Initialize the htmlz websocket server."
76 | (if htmlz-the-server
77 | (htmlz-close-server))
78 | (setq htmlz-the-server
79 | (websocket-server
80 | 3000
81 | :host 'local
82 | :on-open (lambda (ws) (setq htmlz-opened-websocket ws))
83 | :on-close (lambda (ws) (setq htmlz-opened-websocket nil)))))
84 |
85 | (defun htmlz-send-buffer-contents ()
86 | "Sends the contents of the current buffer to the browser."
87 | (if htmlz-opened-websocket
88 | (websocket-send-text htmlz-opened-websocket (buffer-string))
89 | (message "error: no open websocket connection")))
90 |
91 | (defun htmlz-close-server ()
92 | "Closes our websocket server."
93 | (websocket-server-close htmlz-the-server))
94 |
95 | (defun htmlz-start ()
96 | "Startup htmlz."
97 | (htmlz-init-dependencies)
98 | (htmlz-init-file)
99 | (htmlz-init-server)
100 | (htmlz-open-file)
101 | (add-hook 'post-command-hook 'htmlz-send-buffer-contents nil 'local))
102 |
103 | (defun htmlz-finish ()
104 | "Clean up htmlz."
105 | (htmlz-close-server)
106 | (delete-file (htmlz-get-filename))
107 | (remove-hook 'post-command-hook 'htmlz-send-buffer-contents 'local))
108 |
109 | (define-minor-mode htmlz-mode
110 | "The htmlz minor mode"
111 | :lighter " htmlz"
112 | ; This is executed after the macro has toggled the mode. This means
113 | ; that the mode not being on implies that it has been turned off and
114 | ; the mode being on implies that it has been turned on.
115 | (if (not htmlz-mode)
116 | (htmlz-finish)
117 | (htmlz-start)))
118 |
119 | (provide 'htmlz-mode)
120 | ;;; htmlz.el ends here
121 |
--------------------------------------------------------------------------------