forked from 0xekez/htmlz-mode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhtmlz.el
107 lines (89 loc) · 3.15 KB
/
htmlz.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
;;; htmlz --- Simple real-time Emacs html preview
;; Copyright (C) 2020 Zeke Medley
;; Author: Zeke Medley <[email protected]>
;; Keywords: html
;; Version: 0.1
;; URL: https://github.com/ZekeMedley/htmlz
;;; Commentary:
;; htmlz-mode is an Emacs mode that gives a live preview while you
;; edit html. There are other programs that do this and they are
;; reasonably good I'm sure, but they all seem a little more
;; complicated than I'd actually like. This doesn't have any
;; shortcuts or really add anything other than a live preview that
;; starts if you run M-x htmlz-mode from a buffer.
;;
;;; Code:
(require 'browse-url)
(require 'websocket)
(defvar htmlz-opened-websocket nil
"The currently open websocket.")
(defvar htmlz-the-server nil
"The current websocket server. Created after the client opens a websocket connection with us.")
(defun htmlz-get-current-extension ()
"Gets the file extension for the current buffer."
(car (reverse (split-string (buffer-file-name) "\\."))))
(defun htmlz-get-current-dir ()
"Gets the directory for the current buffer."
(file-name-directory (buffer-file-name)))
(defun htmlz-get-filename ()
"Gets the filename for the current buffer."
(concat (htmlz-get-current-dir) "~htmlz-tmp." (htmlz-get-current-extension)))
(defun htmlz-init-file ()
"Create a file for htmlz to load."
(write-region "<!DOCTYPE html>
<script>
const ws = new WebSocket('ws://localhost:3000')
ws.onmessage = function(event) {
// This method, while more pendatic, is much slower.
// document.open()
// document.write(event.data)
// document.close()
document.body.innerHTML = event.data;
}
</script>"
nil (htmlz-get-filename)
nil 'quiet))
(defun htmlz-open-file ()
"Opens the htmlz file in the default browser."
(browse-url (htmlz-get-filename)))
(defun htmlz-init-server ()
"Initialize the htmlz websocket server."
(if htmlz-the-server
(htmlz-close-server))
(setq htmlz-the-server
(websocket-server
3000
:host 'local
:on-open (lambda (ws) (setq htmlz-opened-websocket ws))
:on-close (lambda (ws) (setq htmlz-opened-websocket nil)))))
(defun htmlz-send-buffer-contents ()
"Sends the contents of the current buffer to the browser."
(if htmlz-opened-websocket
(websocket-send-text htmlz-opened-websocket (buffer-string))
(message "error: no open websocket connection")))
(defun htmlz-close-server ()
"Closes our websocket server."
(websocket-server-close htmlz-the-server))
(defun htmlz-start ()
"Startup htmlz."
(htmlz-init-file)
(htmlz-init-server)
(htmlz-open-file)
(add-hook 'post-command-hook 'htmlz-send-buffer-contents nil 'local))
(defun htmlz-finish ()
"Clean up htmlz."
(htmlz-close-server)
(delete-file (htmlz-get-filename))
(remove-hook 'post-command-hook 'htmlz-send-buffer-contents 'local))
;;;###autoload
(define-minor-mode htmlz-mode
"The htmlz minor mode"
:lighter " htmlz"
; This is executed after the macro has toggled the mode. This means
; that the mode not being on implies that it has been turned off and
; the mode being on implies that it has been turned on.
(if (not htmlz-mode)
(htmlz-finish)
(htmlz-start)))
(provide 'htmlz-mode)
;;; htmlz.el ends here