edit_server.el 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. ;;
  2. ;; Emacs edit-server
  3. ;;
  4. ;; This provides an edit server to respond to requests from the Chrome
  5. ;; Emacs Chrome plugin. This is my first attempt at doing something
  6. ;; with sockets in Emacs. I based it on the following examples:
  7. ;;
  8. ;; http://www.emacswiki.org/emacs/EmacsEchoServer
  9. ;; http://nullprogram.com/blog/2009/05/17/
  10. ;;
  11. ;; (C) 2009 Alex Bennee (alex@bennee.com)
  12. ;; Licensed under GPLv3
  13. ;;
  14. ;;
  15. ; still debugging
  16. (setq debug-on-error 't)
  17. (setq edebug-all-defs 't)
  18. ;; Vars
  19. (defvar edit-server-port 9292
  20. "Port the edit server listens too")
  21. (defvar edit-server-current-proc 'nil
  22. "Network process associated with the current edit, made local when
  23. the edit buffer is created")
  24. (defvar edit-server-current-frame 'nil
  25. "The frame created for a new edit-server process, made local when
  26. then edit buffer is created")
  27. (defvar edit-server-clients '()
  28. "alist where KEY is a client process and VALUE is the string")
  29. ;; Mode magic
  30. ;
  31. ; We want to re-map some of the keys to trigger edit-server-done
  32. ; instead of the usual emacs like behaviour. However using
  33. ; local-set-key will affect all buffers of the same mode, hence we
  34. ; define a special (derived) mode for handling editing of text areas.
  35. ;
  36. (defvar edit-server-text-mode-map
  37. (let ((map (make-sparse-keymap)))
  38. (define-key map (kbd "C-x k") 'edit-server-done)
  39. (define-key map (kbd "C-x C-s") 'edit-server-done)
  40. map)
  41. "Keymap for `edit-server-text-mode'.")
  42. (define-derived-mode edit-server-text-mode text-mode "Edit Server Text Mode"
  43. "A derived version of text-mode with a few common Emacs keystrokes
  44. rebound to more functions that can deal with the response to the
  45. edit-server request")
  46. ;; Edit Server socket code
  47. ;
  48. (defun edit-server-start nil
  49. "Start the edit server"
  50. (interactive)
  51. (unless (process-status "edit-server")
  52. (make-network-process
  53. :name "edit-server"
  54. :buffer "*edit-server*"
  55. :family 'ipv4
  56. :host 'local ; only listen to local connections
  57. :service edit-server-port
  58. :filter 'edit-server-filter
  59. :server 't)
  60. (setq edit-server-clients '())
  61. (message "Created a new edit-server process")))
  62. (defun edit-server-stop nil
  63. "Stop the edit server"
  64. (interactive)
  65. (while edit-server-clients
  66. (delete-process (car (car edit-server-clients)))
  67. (setq edit-server-clients (cdr edit-server-clients)))
  68. (if (process-status "edit-server")
  69. (delete-process "edit-server")
  70. (message "No edit server running")))
  71. ; Write log entries
  72. (defun edit-server-log (string &optional client)
  73. "If a *edit-server* buffer exists, write STRING to it for logging purposes."
  74. (if (get-buffer "*edit-server*")
  75. (with-current-buffer "*edit-server*"
  76. (goto-char (point-max))
  77. (insert (current-time-string)
  78. (if client (format " %s:" client) " ")
  79. string)
  80. (or (bolp) (newline)))))
  81. (defun edit-server-split-request (msg)
  82. "Split the request into headers/content"
  83. (let* ((split-request (split-string msg "\n\n"))
  84. (headers (car split-request))
  85. (after-headers (cdr split-request))
  86. (content (car after-headers))
  87. (rest (cdr after-headers)))
  88. (if rest
  89. (dolist (x rest)
  90. (setq content (concat content "\n\n" x))))
  91. (list headers content)))
  92. (defun edit-server-filter (proc string)
  93. "Called each time something connects to the edit server"
  94. (let ((pending (assoc proc edit-server-clients))
  95. message)
  96. ;;create entry if required
  97. (unless pending
  98. (setq edit-server-clients (cons (cons proc "") edit-server-clients))
  99. (setq pending (assoc proc edit-server-clients)))
  100. (setq message (concat (cdr pending) string))
  101. (edit-server-log (format "edit-server-filter: s:%s" string))
  102. (edit-server-log (format "edit-server-filter: m:%s" message))
  103. ;; Get the content from the headers, we don't actually much care
  104. ;; about the headers for now. I suspect this would break on Windows
  105. ;;
  106. ;; As we split on \n\n we need to re-assemble to take into account
  107. ;; any multiple new lines in our content part.
  108. (let* ((split-request (edit-server-split-request message))
  109. (headers (car split-request))
  110. (content (car (cdr split-request))))
  111. (edit-server-create-edit-buffer proc content))))
  112. (defun edit-server-create-edit-buffer(proc string)
  113. "Create an edit buffer, place content in it and save the network
  114. process for the final call back"
  115. (let ((name (generate-new-buffer-name "edit-server-text-buffer")))
  116. (switch-to-buffer-other-frame name)
  117. ; (switch-to-buffer name)
  118. (with-current-buffer name
  119. (set (make-local-variable 'edit-server-current-proc) proc)
  120. (set (make-local-variable 'edit-server-current-frame) (selected-frame))
  121. (if string
  122. (insert string)
  123. (insert "Empty text box (this may be a bug)"))
  124. (edit-server-text-mode))))
  125. ;
  126. ; Send the response back to the browser as a properly formed
  127. ; HTTP/1.0 200 OK message
  128. ;
  129. (defun edit-server-send-response (proc string)
  130. "Send a response back to the calling process with a string"
  131. (interactive)
  132. (message "edit-server-send-response")
  133. (if proc
  134. (let ((response-header (concat
  135. "HTTP/1.0 200 OK\n"
  136. "Server: Emacs\n"
  137. "Date: "
  138. (format-time-string
  139. "%a, %d %b %Y %H:%M:%S GMT\n"
  140. (current-time)))))
  141. (process-send-string proc response-header)
  142. (process-send-string proc "\n")
  143. (process-send-string proc string)
  144. (process-send-eof proc))
  145. (message "edit-server-send-response: null proc (bug?)")))
  146. (defun edit-server-done()
  147. "Once someone is done with editing their text edit-server-done is
  148. called and the response is sent back to the browser"
  149. (interactive)
  150. (edit-server-send-response edit-server-current-proc (buffer-string))
  151. (delete-frame edit-server-current-frame)
  152. (kill-buffer))