From: Stefan Bund Date: Fri, 18 Jan 2019 16:38:15 +0000 (+0100) Subject: update X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=a13a166794e1e6f22407e13110fe83b9cb095ab8;p=emacs-init.git update --- diff --git a/UBUNTU-PACKAGES b/UBUNTU-PACKAGES index d09c225..e78deb1 100644 --- a/UBUNTU-PACKAGES +++ b/UBUNTU-PACKAGES @@ -4,4 +4,5 @@ python-ropemacs pyflakes cmake llvm -libclang-dev \ No newline at end of file +libclang-dev +yaml-mode diff --git a/auto-install/atomic-chrome.el b/auto-install/atomic-chrome.el new file mode 100644 index 0000000..f1750da --- /dev/null +++ b/auto-install/atomic-chrome.el @@ -0,0 +1,368 @@ +;;; atomic-chrome.el --- Edit Chrome text area with Emacs using Atomic Chrome + +;; Copyright (C) 2016 alpha22jp + +;; Author: alpha22jp +;; Package-Requires: ((emacs "24.3") (let-alist "1.0.4") (websocket "1.4")) +;; Package-Version: 20171022.107 +;; Keywords: chrome edit textarea +;; URL: https://github.com/alpha22jp/atomic-chrome +;; Version: 2.0.0 + +;; This program is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free Software +;; Foundation; either version 2 of the License, or (at your option) any later +;; version. + +;; This program is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +;; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +;; details. + +;; You should have received a copy of the GNU General Public License along with +;; this program; if not, write to the Free Software Foundation, Inc., 51 +;; Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; This is the Emacs version of Atomic Chrome which is an extension for Google +;; Chrome browser that allows you to edit text areas of the browser in Emacs. +;; +;; It's similar to Edit with Emacs, but has some advantages as below with the +;; help of websocket. +;; +;; * Live update +;; The input on Emacs is reflected to the browser instantly and continuously. +;; * Bidirectional communication +;; You can edit both on the browser and Emacs, they are synced to the same. + +;;; Code: + +(eval-when-compile (require 'cl)) +(require 'json) +(require 'let-alist) +(require 'websocket) + +(defgroup atomic-chrome nil + "Edit Chrome text area with Emacs using Atomic Chrome." + :prefix "atomic-chrome-" + :group 'applications) + +(defcustom atomic-chrome-extension-type-list '(atomic-chrome ghost-text) + "List of chrome extension type available." + :type '(repeat (choice (const :tag "Atomic Chrome" atomic-chrome) + (const :tag "Ghost Text" ghost-text))) + :group 'atomic-chrome) + +(defcustom atomic-chrome-buffer-open-style 'split + "Specify the style to open new buffer for editing." + :type '(choice (const :tag "Open buffer with full window" full) + (const :tag "Open buffer with splitted window" split) + (const :tag "Open buffer with new frame" frame)) + :group 'atomic-chrome) + +(defcustom atomic-chrome-buffer-frame-width 80 + "Width of editing buffer frame." + :type 'integer + :group 'atomic-chrome) + +(defcustom atomic-chrome-buffer-frame-height 25 + "Height of editing buffer frame." + :type 'integer + :group 'atomic-chrome) + +(defcustom atomic-chrome-enable-auto-update t + "If non-nil, edit on Emacs is reflected to Chrome instantly, \ +otherwise you need to type \"C-xC-s\" manually." + :type 'boolean + :group 'atomic-chrome) + +(defcustom atomic-chrome-enable-bidirectional-edit t + "If non-nil, you can edit both on Chrome text area and Emacs, \ +otherwise edit on Chrome is ignored while editing on Emacs." + :type 'boolean + :group 'atomic-chrome) + +(defcustom atomic-chrome-default-major-mode 'text-mode + "Default major mode for editing buffer." + :type 'function + :group 'atomic-chrome) + +(defcustom atomic-chrome-url-major-mode-alist nil + "Association list of URL regexp and corresponding major mode \ +which is used to select major mode for specified website." + :type '(alist :key-type (regexp :tag "regexp") + :value-type (function :tag "major mode")) + :group 'atomic-chrome) + +(defcustom atomic-chrome-edit-mode-hook nil + "Customizable hook which run when the editing buffer is created." + :type 'hook + :group 'atomic-chrome) + +(defcustom atomic-chrome-edit-done-hook nil + "Customizable hook which run when the editing buffer is closed." + :type 'hook + :group 'atomic-chrome) + +(defvar atomic-chrome-server-atomic-chrome nil + "Websocket server connection handle for Atomic Chrome.") + +(defvar atomic-chrome-server-ghost-text nil + "Websocket server connection handle for Ghost Text.") + +(defvar atomic-chrome-buffer-table (make-hash-table :test 'equal) + "Hash table of editing buffer and its assciated data. +Each element has a list consisting of (websocket, frame).") + +(defun atomic-chrome-get-websocket (buffer) + "Lookup websocket associated with buffer BUFFER \ +from `atomic-chrome-buffer-table'." + (nth 0 (gethash buffer atomic-chrome-buffer-table))) + +(defun atomic-chrome-get-frame (buffer) + "Lookup frame associated with buffer BUFFER \ +from `atomic-chrome-buffer-table'." + (nth 1 (gethash buffer atomic-chrome-buffer-table))) + +(defun atomic-chrome-get-buffer-by-socket (socket) + "Lookup buffer which is associated to the websocket SOCKET \ +from `atomic-chrome-buffer-table'." + (let (buffer) + (cl-loop for key being the hash-keys of atomic-chrome-buffer-table + using (hash-values val) + do (when (equal (nth 0 val) socket) (setq buffer key))) + buffer)) + +(defun atomic-chrome-close-connection () + "Close client connection associated with current buffer." + (let ((socket (atomic-chrome-get-websocket (current-buffer)))) + (when socket + (remhash (current-buffer) atomic-chrome-buffer-table) + (websocket-close socket)))) + +(defun atomic-chrome-send-buffer-text () + "Send request to update text with current buffer content." + (interactive) + (let ((socket (atomic-chrome-get-websocket (current-buffer))) + (text (buffer-substring-no-properties (point-min) (point-max)))) + (when (and socket text) + (websocket-send-text + socket + (json-encode + (if (eq (websocket-server-conn socket) atomic-chrome-server-ghost-text) + (list (cons "text" text)) + (list '("type" . "updateText") + (cons "payload" (list (cons "text" text)))))))))) + +(defun atomic-chrome-set-major-mode (url) + "Set major mode for editing buffer depending on URL. +`atomic-chrome-url-major-mode-alist' can be used to select major mode. +The specified major mode is used if URL matches to one of the alist, +otherwise fallback to `atomic-chrome-default-major-mode'" + (funcall (or (and url (assoc-default url + atomic-chrome-url-major-mode-alist + 'string-match)) + atomic-chrome-default-major-mode))) + +(defun atomic-chrome-show-edit-buffer (buffer title) + "Show editing buffer BUFFER by creating a frame with title TITLE, \ +or raising the selected frame depending on `atomic-chrome-buffer-open-style'." + (let ((edit-frame nil) + (frame-params (list (cons 'name (format "Atomic Chrome: %s" title)) + (cons 'width atomic-chrome-buffer-frame-width) + (cons 'height atomic-chrome-buffer-frame-height)))) + (when (eq atomic-chrome-buffer-open-style 'frame) + (setq edit-frame + (if (memq window-system '(ns mac)) + ;; Avoid using make-frame-on-display for Mac OS. + (make-frame frame-params) + (make-frame-on-display + (if (eq system-type 'windows-nt) "w32" (getenv "DISPLAY")) + frame-params))) + (select-frame edit-frame)) + (if (eq atomic-chrome-buffer-open-style 'split) + (pop-to-buffer buffer) + (switch-to-buffer buffer)) + (raise-frame edit-frame) + (select-frame-set-input-focus (window-frame (selected-window))) + edit-frame)) + +(defun atomic-chrome-create-buffer (socket url title text) + "Create buffer associated with websocket specified by SOCKET. +URL is used to determine the major mode of the buffer created, +TITLE is used for the buffer name and TEXT is inserted to the buffer." + (let ((buffer (generate-new-buffer title))) + (with-current-buffer buffer + (puthash buffer + (list socket (atomic-chrome-show-edit-buffer buffer title)) + atomic-chrome-buffer-table) + (atomic-chrome-set-major-mode url) + (insert text)))) + +(defun atomic-chrome-close-edit-buffer (buffer) + "Close buffer BUFFER if it's one of Atomic Chrome edit buffers." + (let ((frame (atomic-chrome-get-frame buffer))) + (with-current-buffer buffer + (save-restriction + (run-hooks 'atomic-chrome-edit-done-hook) + (when frame (delete-frame frame)) + (if (eq atomic-chrome-buffer-open-style 'split) + (quit-window t) + (kill-buffer buffer)))))) + +(defun atomic-chrome-close-current-buffer () + "Close current buffer and connection from client." + (interactive) + (atomic-chrome-close-edit-buffer (current-buffer))) + +(defun atomic-chrome-update-buffer (socket text) + "Update text on buffer associated with SOCKET to TEXT." + (let ((buffer (atomic-chrome-get-buffer-by-socket socket))) + (when buffer + (with-current-buffer buffer + (erase-buffer) + (insert text))))) + +(defun atomic-chrome-on-message (socket frame) + "Function to handle data received from websocket client specified by SOCKET, \ +where FRAME show raw data received." + (let ((msg (json-read-from-string + (decode-coding-string + (encode-coding-string (websocket-frame-payload frame) 'utf-8) + 'utf-8)))) + (let-alist msg + (if (eq (websocket-server-conn socket) atomic-chrome-server-ghost-text) + (if (atomic-chrome-get-buffer-by-socket socket) + (atomic-chrome-update-buffer socket .text) + (atomic-chrome-create-buffer socket .url .title .text)) + (cond ((string= .type "register") + (atomic-chrome-create-buffer socket .payload.url .payload.title .payload.text)) + ((string= .type "updateText") + (when atomic-chrome-enable-bidirectional-edit + (atomic-chrome-update-buffer socket .payload.text)))))))) + +(defun atomic-chrome-on-close (socket) + "Function to handle request from client to close websocket SOCKET." + (let ((buffer (atomic-chrome-get-buffer-by-socket socket))) + (when buffer (atomic-chrome-close-edit-buffer buffer)))) + +(defvar atomic-chrome-edit-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-x C-s") 'atomic-chrome-send-buffer-text) + (define-key map (kbd "C-c C-c") 'atomic-chrome-close-current-buffer) + map) + "Keymap for minor mode `atomic-chrome-edit-mode'.") + +(define-minor-mode atomic-chrome-edit-mode + "Minor mode enabled on buffers opened by Emacs Chrome server." + :group 'atomic-chrome + :lighter " AtomicChrome" + :init-value nil + :keymap atomic-chrome-edit-mode-map + (when atomic-chrome-edit-mode + (add-hook 'kill-buffer-hook 'atomic-chrome-close-connection nil t) + (when atomic-chrome-enable-auto-update + (add-hook 'post-command-hook 'atomic-chrome-send-buffer-text nil t)))) + +(defun atomic-chrome-turn-on-edit-mode () + "Turn on `atomic-chrome-edit-mode' if the buffer is an editing buffer." + (when (gethash (current-buffer) atomic-chrome-buffer-table) + (atomic-chrome-edit-mode t))) + +(define-global-minor-mode global-atomic-chrome-edit-mode + atomic-chrome-edit-mode atomic-chrome-turn-on-edit-mode) + +(defun atomic-chrome-start-websocket-server (port) + "Create websocket server on port PORT." + (websocket-server + port + :host 'local + :on-message #'atomic-chrome-on-message + :on-open nil + :on-close #'atomic-chrome-on-close)) + +(defun atomic-chrome-start-httpd () + "Start the HTTP server for Ghost Text query." + (interactive) + (make-network-process + :name "atomic-chrome-httpd" + :family 'ipv4 + :host 'local + :service 4001 + :filter 'atomic-chrome-httpd-process-filter + :filter-multibyte nil + :server t + :noquery t)) + +(defun atomic-chrome-normalize-header (header) + "Destructively capitalize the components of HEADER." + (mapconcat #'capitalize (split-string header "-") "-")) + +(defun atomic-chrome-httpd-parse-string (string) + "Parse client http header STRING into alist." + (let* ((lines (split-string string "[\n\r]+")) + (req (list (split-string (car lines)))) + (post (cadr (split-string string "\r\n\r\n")))) + (dolist (line (butlast (cdr lines))) + (push (list (atomic-chrome-normalize-header (car (split-string line ": "))) + (mapconcat #'identity + (cdr (split-string line ": ")) ": ")) + req)) + (push (list "Content" post) req) + (reverse req))) + +(defun atomic-chrome-httpd-process-filter (proc string) + "Process filter of PROC which run each time client make a request. +STRING is the string process received." + (setf string (concat (process-get proc :previous-string) string)) + (let* ((request (atomic-chrome-httpd-parse-string string)) + (content-length (cadr (assoc "Content-Length" request))) + (uri (cl-cadar request)) + (content (cadr (assoc "Content" request)))) + (if (and content-length + (< (string-bytes content) (string-to-number content-length))) + (process-put proc :previous-string string) + (atomic-chrome-httpd-send-response proc)))) + +(defun atomic-chrome-httpd-send-response (proc) + "Send an HTTP 200 OK response back to process PROC." + (when (processp proc) + (unless atomic-chrome-server-ghost-text + (setq atomic-chrome-server-ghost-text + (atomic-chrome-start-websocket-server 64293))) + (let ((header "HTTP/1.0 200 OK\nContent-Type: application/json\n") + (body (json-encode '(:ProtocolVersion 1 :WebSocketPort 64293)))) + (process-send-string proc (concat header "\n" body)) + (process-send-eof proc)))) + +;;;###autoload +(defun atomic-chrome-start-server () + "Start websocket server for atomic-chrome." + (interactive) + (and (not atomic-chrome-server-atomic-chrome) + (memq 'atomic-chrome atomic-chrome-extension-type-list) + (setq atomic-chrome-server-atomic-chrome + (atomic-chrome-start-websocket-server 64292))) + (and (not (process-status "atomic-chrome-httpd")) + (memq 'ghost-text atomic-chrome-extension-type-list) + (atomic-chrome-start-httpd)) + (global-atomic-chrome-edit-mode 1)) + +;;;###autoload +(defun atomic-chrome-stop-server nil + "Stop websocket server for atomic-chrome." + (interactive) + (when atomic-chrome-server-atomic-chrome + (websocket-server-close atomic-chrome-server-atomic-chrome) + (setq atomic-chrome-server-atomic-chrome nil)) + (when atomic-chrome-server-ghost-text + (websocket-server-close atomic-chrome-server-ghost-text) + (setq atomic-chrome-server-ghost-text nil)) + (when (process-status "atomic-chrome-httpd") + (delete-process "atomic-chrome-httpd")) + (global-atomic-chrome-edit-mode 0)) + +(provide 'atomic-chrome) + +;;; atomic-chrome.el ends here diff --git a/elpa/archives/gnu/archive-contents b/elpa/archives/gnu/archive-contents new file mode 100644 index 0000000..2b1441e --- /dev/null +++ b/elpa/archives/gnu/archive-contents @@ -0,0 +1,1179 @@ +(1 + (ace-window . + [(0 9 0) + ((avy + (0 2 0))) + "Quickly switch windows." single + ((:url . "https://github.com/abo-abo/ace-window") + (:keywords "window" "location"))]) + (ack . + [(1 5) + nil "interface to ack-like tools" tar + ((:keywords "tools" "processes" "convenience") + (:url . "https://github.com/leoliu/ack-el"))]) + (ada-mode . + [(5 3 1) + ((wisi + (1 1 6)) + (cl-lib + (0 4)) + (emacs + (24 3))) + "major-mode for editing Ada sources" tar + ((:keywords "languages" "ada") + (:url . "http://www.nongnu.org/ada-mode/"))]) + (ada-ref-man . + [(2012 3) + nil "Ada Reference Manual 2012" tar + ((:keywords "languages" "ada") + (:url . "http://stephe-leake.org/ada/arm.html"))]) + (adaptive-wrap . + [(0 5 1) + nil "Smart line-wrapping with wrap-prefix" single + ((:url . "http://elpa.gnu.org/packages/adaptive-wrap.html") + (:keywords))]) + (adjust-parens . + [(3 0) + nil "Indent and dedent Lisp code, automatically adjust close parens" tar + ((:url . "http://elpa.gnu.org/packages/adjust-parens.html"))]) + (aggressive-indent . + [(1 8 3) + ((emacs + (24 1)) + (cl-lib + (0 5))) + "Minor mode to aggressively keep your code always indented" single + ((:url . "https://github.com/Malabarba/aggressive-indent-mode") + (:keywords "indent" "lisp" "maint" "tools"))]) + (ahungry-theme . + [(1 5 0) + ((emacs + (24))) + "Ahungry color theme for Emacs. Make sure to (load-theme 'ahungry)." tar + ((:keywords "ahungry" "palette" "color" "theme" "emacs" "color-theme" "deftheme") + (:url . "https://github.com/ahungry/color-theme-ahungry"))]) + (all . + [(1 0) + nil "Edit all lines matching a given regexp" single + ((:url . "http://elpa.gnu.org/packages/all.html") + (:keywords "matching"))]) + (ampc . + [(0 2) + nil "Asynchronous Music Player Controller" single + ((:url . "http://elpa.gnu.org/packages/ampc.html") + (:keywords "ampc" "mpc" "mpd"))]) + (arbitools . + [(0 71) + ((cl-lib + (0 5))) + "Package for chess tournaments administration" single + ((:url . "http://elpa.gnu.org/packages/arbitools.html") + (:keywords))]) + (ascii-art-to-unicode . + [(1 11) + nil "a small artist adjunct" single + ((:url . "http://www.gnuvola.org/software/aa2u/") + (:keywords "ascii" "unicode" "box-drawing"))]) + (async . + [(1 9 2) + nil "Asynchronous processing in Emacs" tar + ((:keywords "async") + (:url . "http://elpa.gnu.org/packages/async.html"))]) + (auctex . + [(11 91 0) + nil "Integrated environment for *TeX*" tar + ((:url . "http://www.gnu.org/software/auctex/"))]) + (aumix-mode . + [(7) + nil "run the aumix program in a buffer" single + ((:url . "http://user42.tuxfamily.org/aumix-mode/index.html") + (:keywords "multimedia" "mixer" "aumix"))]) + (auto-correct . + [(1 1) + nil "Remembers and automatically fixes past corrections" single + ((:url . "http://elpa.gnu.org/packages/auto-correct.html") + (:keywords "editing"))]) + (auto-overlays . + [(0 10 9) + nil "Automatic regexp-delimited overlays" tar + ((:keywords "extensions") + (:url . "http://www.dr-qubit.org/emacs.php"))]) + (avy . + [(0 4 0) + ((emacs + (24 1)) + (cl-lib + (0 5))) + "tree-based completion" tar + ((:keywords "point" "location") + (:url . "https://github.com/abo-abo/avy"))]) + (beacon . + [(1 3 2) + ((seq + (2 14))) + "Highlight the cursor whenever the window scrolls" single + ((:url . "https://github.com/Malabarba/beacon") + (:keywords "convenience"))]) + (bug-hunter . + [(1 3 1) + ((seq + (1 3)) + (cl-lib + (0 5))) + "Hunt down errors by bisecting elisp files" single + ((:url . "https://github.com/Malabarba/elisp-bug-hunter") + (:keywords "lisp"))]) + (caps-lock . + [(1 0) + nil "Caps-lock as a minor mode" single + ((:url . "http://elpa.gnu.org/packages/caps-lock.html") + (:keywords))]) + (captain . + [(1 0 1) + nil "CAPiTalization is Automatic IN emacs" single + ((:url . "http://elpa.gnu.org/packages/captain.html") + (:keywords "editing"))]) + (chess . + [(2 0 4) + ((cl-lib + (0 5))) + "Play chess in GNU Emacs" tar + ((:keywords "games") + (:url . "http://elpa.gnu.org/packages/chess.html"))]) + (cl-generic . + [(0 3) + nil "Forward cl-generic compatibility for Emacs<25" single + ((:url . "http://elpa.gnu.org/packages/cl-generic.html") + (:keywords))]) + (cl-lib . + [(0 6 1) + nil "Properly prefixed CL functions and macros" single + ((:url . "http://elpa.gnu.org/packages/cl-lib.html") + (:keywords))]) + (cl-print . + [(1 0) + ((emacs + (25))) + "CL-style generic printing" single + ((:url . "http://elpa.gnu.org/packages/cl-print.html") + (:keywords))]) + (cobol-mode . + [(1 0 0) + ((cl-lib + (0 5))) + "Mode for editing COBOL code" single + ((:url . "http://elpa.gnu.org/packages/cobol-mode.html") + (:keywords "languages"))]) + (coffee-mode . + [(0 4 1 1) + nil "Major mode for CoffeeScript files" single + ((:url . "http://github.com/defunkt/coffee-mode") + (:keywords "coffeescript" "major" "mode"))]) + (compact-docstrings . + [(0 1) + nil "Shrink blank lines in docstrings and doc comments" single + ((:url . "https://github.com/cpitclaudel/compact-docstrings") + (:keywords "convenience" "faces" "lisp" "maint" "c"))]) + (company . + [(0 9 4) + ((emacs + (24 3))) + "Modular text completion framework" tar + ((:keywords "abbrev" "convenience" "matching") + (:url . "http://company-mode.github.io/"))]) + (company-ebdb . + [(1) + ((company + (0 9 4)) + (ebdb + (0 2))) + "company-mode completion backend for EBDB in message-mode" single + ((:url . "http://elpa.gnu.org/packages/company-ebdb.html") + (:keywords))]) + (company-math . + [(1 1) + ((company + (0 8 0)) + (math-symbol-lists + (1 0))) + "Completion backends for unicode math symbols and latex tags" tar + ((:keywords "unicode" "symbols" "completion") + (:url . "https://github.com/vspinu/company-math"))]) + (company-statistics . + [(0 2 3) + ((emacs + (24 3)) + (company + (0 8 5))) + "Sort candidates using completion history" tar + ((:keywords "abbrev" "convenience" "matching") + (:url . "https://github.com/company-mode/company-statistics"))]) + (context-coloring . + [(8 1 0) + ((emacs + (24 3))) + "Highlight by scope" tar + ((:keywords "convenience" "faces" "tools") + (:url . "https://github.com/jacksonrayhamilton/context-coloring"))]) + (counsel-ebdb . + [(1) + ((ivy + (0 8 0)) + (ebdb + (0 2))) + "Counsel integration for EBDB" single + ((:url . "http://elpa.gnu.org/packages/counsel-ebdb.html") + (:keywords))]) + (crisp . + [(1 3 4) + nil "CRiSP/Brief Emacs emulator" single + ((:url . "http://elpa.gnu.org/packages/crisp.html") + (:keywords "emulations" "brief" "crisp"))]) + (csv-mode . + [(1 6) + nil "Major mode for editing comma/char separated values" single + ((:url . "http://elpa.gnu.org/packages/csv-mode.html") + (:keywords "convenience"))]) + (cycle-quotes . + [(0 1) + nil "Cycle between quote styles" tar + ((:keywords "convenience") + (:url . "http://elpa.gnu.org/packages/cycle-quotes.html"))]) + (darkroom . + [(0 1) + ((cl-lib + (0 5))) + "Remove visual distractions and focus on writing" single + ((:url . "http://elpa.gnu.org/packages/darkroom.html") + (:keywords "convenience" "emulations"))]) + (dash . + [(2 12 0) + nil "A modern list library for Emacs" tar + ((:keywords "lists") + (:url . "http://elpa.gnu.org/packages/dash.html"))]) + (dbus-codegen . + [(0 1) + ((cl-lib + (0 5))) + "Lisp code generation for D-Bus." single + ((:url . "http://elpa.gnu.org/packages/dbus-codegen.html") + (:keywords "comm" "dbus" "convenience"))]) + (debbugs . + [(0 14) + ((soap-client + (3 1 1)) + (cl-lib + (0 5))) + "SOAP library to access debbugs servers" tar + ((:keywords "comm" "hypermedia") + (:url . "http://elpa.gnu.org/packages/debbugs.html"))]) + (delight . + [(1 5) + nil "A dimmer switch for your lighter text." single + ((:url . "https://savannah.nongnu.org/projects/delight") + (:keywords "convenience"))]) + (dict-tree . + [(0 14) + ((trie + (0 3)) + (tNFA + (0 1 1)) + (heap + (0 3))) + "Dictionary data structure" single + ((:url . "http://www.dr-qubit.org/emacs.php") + (:keywords "extensions" "matching" "data structures trie" "tree" "dictionary" "completion" "regexp"))]) + (diff-hl . + [(1 8 4) + ((cl-lib + (0 2))) + "Highlight uncommitted changes using VC" tar + ((:keywords "vc" "diff") + (:url . "https://github.com/dgutov/diff-hl"))]) + (diffview . + [(1 0) + nil "View diffs in side-by-side format" single + ((:url . "https://github.com/mgalgs/diffview-mode") + (:keywords "convenience" "diff"))]) + (dired-du . + [(0 5) + ((emacs + (24 4)) + (cl-lib + (0 5))) + "Dired with recursive directory sizes" tar + ((:keywords "files" "unix" "convenience") + (:url . "http://elpa.gnu.org/packages/dired-du.html"))]) + (dismal . + [(1 5) + ((cl-lib + (0))) + "Dis Mode Ain't Lotus: Spreadsheet program Emacs" tar + ((:url . "http://elpa.gnu.org/packages/dismal.html"))]) + (djvu . + [(0 5) + nil "Edit and view Djvu files via djvused" single + ((:url . "http://elpa.gnu.org/packages/djvu.html") + (:keywords "files" "wp"))]) + (docbook . + [(0 1) + nil "Info-like viewer for DocBook" single + ((:url . "http://elpa.gnu.org/packages/docbook.html") + (:keywords "docs" "help"))]) + (dts-mode . + [(0 1 0) + nil "Major mode for Device Tree source files" single + ((:url . "http://elpa.gnu.org/packages/dts-mode.html") + (:keywords "languages"))]) + (easy-kill . + [(0 9 3) + ((emacs + (24)) + (cl-lib + (0 5))) + "kill & mark things easily" tar + ((:keywords "killing" "convenience") + (:url . "https://github.com/leoliu/easy-kill"))]) + (ebdb . + [(0 3 3) + ((emacs + (25 1)) + (cl-lib + (0 5)) + (seq + (2 15))) + "Contact management package" tar + ((:keywords "convenience" "mail") + (:url . "https://github.com/girzel/ebdb"))]) + (ebdb-gnorb . + [(1 0 2) + ((gnorb + (1 1 0)) + (ebdb + (0 2))) + "Utilities for connecting EBDB to Gnorb" single + ((:url . "http://elpa.gnu.org/packages/ebdb-gnorb.html") + (:keywords))]) + (ebdb-i18n-chn . + [(1 2) + ((pyim + (1 6 0)) + (ebdb + (0 2))) + "China-specific internationalization support for EBDB" single + ((:url . "http://elpa.gnu.org/packages/ebdb-i18n-chn.html") + (:keywords))]) + (ediprolog . + [(1 2) + nil "Emacs Does Interactive Prolog" single + ((:url . "http://elpa.gnu.org/packages/ediprolog.html") + (:keywords "languages" "processes"))]) + (el-search . + [(1 3 2) + ((emacs + (25)) + (stream + (2 2 4))) + "Expression based interactive search for Emacs Lisp" tar + ((:keywords "lisp") + (:url . "http://elpa.gnu.org/packages/el-search.html"))]) + (eldoc-eval . + [(0 1) + nil "Enable eldoc support when minibuffer is in use." single + ((:url . "http://elpa.gnu.org/packages/eldoc-eval.html") + (:keywords))]) + (electric-spacing . + [(5 0) + nil "Insert operators with surrounding spaces smartly" single + ((:url . "http://elpa.gnu.org/packages/electric-spacing.html") + (:keywords))]) + (enwc . + [(2 0) + ((emacs + (25 1))) + "The Emacs Network Client" tar + ((:keywords "external" "network" "wicd" "manager" "nm") + (:url . "http://elpa.gnu.org/packages/enwc.html"))]) + (epoch-view . + [(0 0 1) + nil "Minor mode to visualize epoch timestamps" single + ((:url . "http://elpa.gnu.org/packages/epoch-view.html") + (:keywords "data" "timestamp" "epoch" "unix"))]) + (ergoemacs-mode . + [(5 14 7 3) + ((emacs + (24 1)) + (undo-tree + (0 6 5))) + "Emacs mode based on common modern interface and ergonomics." tar + ((:keywords "convenience") + (:url . "https://github.com/ergoemacs/ergoemacs-mode"))]) + (excorporate . + [(0 7 6) + ((emacs + (24 1)) + (fsm + (0 2)) + (soap-client + (3 1 1)) + (url-http-ntlm + (2 0 3))) + "Exchange integration" tar + ((:keywords "calendar") + (:url . "http://elpa.gnu.org/packages/excorporate.html"))]) + (exwm . + [(0 15) + ((xelb + (0 12))) + "Emacs X Window Manager" tar + ((:keywords "unix") + (:url . "https://github.com/ch11ng/exwm"))]) + (f90-interface-browser . + [(1 1) + nil "Parse and browse f90 interfaces" single + ((:url . "http://github.com/wence-/f90-iface/") + (:keywords))]) + (flylisp . + [(0 2) + ((emacs + (24 1)) + (cl-lib + (0 4))) + "Color unbalanced parentheses and parentheses inconsistent with indentation" single + ((:url . "http://elpa.gnu.org/packages/flylisp.html") + (:keywords))]) + (fsm . + [(0 2 1) + ((emacs + (24 1)) + (cl-lib + (0 5))) + "state machine library" single + ((:url . "http://elpa.gnu.org/packages/fsm.html") + (:keywords "extensions"))]) + (ggtags . + [(0 8 12) + ((emacs + (24)) + (cl-lib + (0 5))) + "emacs frontend to GNU Global source code tagging system" single + ((:url . "https://github.com/leoliu/ggtags") + (:keywords "tools" "convenience"))]) + (gited . + [(0 3 3) + ((emacs + (24 4)) + (cl-lib + (0 5))) + "Operate on Git branches like dired" tar + ((:keywords "git" "vc" "convenience") + (:url . "http://elpa.gnu.org/packages/gited.html"))]) + (gnome-c-style . + [(0 1) + nil "minor mode for editing GNOME-style C source code" tar + ((:keywords "gnome" "c" "coding style") + (:url . "http://elpa.gnu.org/packages/gnome-c-style.html"))]) + (gnorb . + [(1 2 4) + ((cl-lib + (0 5))) + "Glue code between Gnus, Org, and BBDB" tar + ((:keywords "mail" "org" "gnus" "bbdb" "todo" "task") + (:url . "http://elpa.gnu.org/packages/gnorb.html"))]) + (gnugo . + [(3 1 0) + ((ascii-art-to-unicode + (1 5)) + (xpm + (1 0 1)) + (cl-lib + (0 5))) + "play GNU Go in a buffer" tar + ((:keywords "games" "processes") + (:url . "http://www.gnuvola.org/software/gnugo/"))]) + (heap . + [(0 5) + nil "Heap (a.k.a. priority queue) data structure" single + ((:url . "http://www.dr-qubit.org/emacs.php") + (:keywords "extensions" "data structures" "heap" "priority queue"))]) + (helm-ebdb . + [(1) + ((helm + (1 0)) + (ebdb + (0 2))) + "Helm integration for EBDB" single + ((:url . "http://elpa.gnu.org/packages/helm-ebdb.html") + (:keywords "mail" "convenience"))]) + (highlight-escape-sequences . + [(0 3) + nil "Highlight escape sequences" single + ((:url . "https://github.com/dgutov/highlight-escape-sequences") + (:keywords "convenience"))]) + (hook-helpers . + [(1 1) + ((emacs + (25 1))) + "Anonymous, modifiable hook functions" tar + ((:keywords "development" "hooks") + (:url . "https://savannah.nongnu.org/projects/hook-helpers-el/"))]) + (html5-schema . + [(0 1) + nil "Add HTML5 schemas for use by nXML" tar + ((:keywords "html" "xml") + (:url . "https://github.com/validator/validator"))]) + (hydra . + [(0 14 0) + ((cl-lib + (0 5))) + "Make bindings that stick around." tar + ((:keywords "bindings") + (:url . "https://github.com/abo-abo/hydra"))]) + (hyperbole . + [(6 0 2) + ((emacs + (24 4))) + "GNU Hyperbole: The Everyday Hypertextual Information Manager" tar + ((:keywords "comm" "convenience" "files" "frames" "hypermedia" "languages" "mail" "matching" "mouse" "multimedia" "outlines" "tools" "wp") + (:url . "http://www.gnu.org/software/hyperbole"))]) + (ioccur . + [(2 4) + nil "Incremental occur" single + ((:url . "http://elpa.gnu.org/packages/ioccur.html") + (:keywords))]) + (iterators . + [(0 1) + ((emacs + (25))) + "Functions for working with iterators" single + ((:url . "http://elpa.gnu.org/packages/iterators.html") + (:keywords "extensions" "elisp"))]) + (ivy . + [(0 9 1) + ((emacs + (24 1))) + "Incremental Vertical completYon" tar + ((:keywords "matching") + (:url . "https://github.com/abo-abo/swiper"))]) + (javaimp . + [(0 6) + nil "Add and reorder Java import statements in Maven projects" tar + ((:keywords "java" "maven" "programming") + (:url . "http://elpa.gnu.org/packages/javaimp.html"))]) + (jgraph-mode . + [(1 1) + ((cl-lib + (0 5))) + "Major mode for Jgraph files" single + ((:url . "http://elpa.gnu.org/packages/jgraph-mode.html") + (:keywords "tex" "wp"))]) + (js2-mode . + [(20170721) + ((emacs + (24 1)) + (cl-lib + (0 5))) + "Improved JavaScript editing mode" tar + ((:keywords "languages" "javascript") + (:url . "https://github.com/mooz/js2-mode/"))]) + (json-mode . + [(0 1) + ((emacs + (25 1))) + "Major mode for editing JSON files" single + ((:url . "http://elpa.gnu.org/packages/json-mode.html") + (:keywords "data"))]) + (jumpc . + [(3 0) + nil "jump to previous insertion points" single + ((:url . "http://elpa.gnu.org/packages/jumpc.html") + (:keywords))]) + (kmb . + [(0 1) + ((emacs + (24 1))) + "Kill buffers matching a regexp w/o confirmation" single + ((:url . "http://elpa.gnu.org/packages/kmb.html") + (:keywords "lisp" "convenience"))]) + (landmark . + [(1 0) + nil "Neural-network robot that learns landmarks" single + ((:url . "http://elpa.gnu.org/packages/landmark.html") + (:keywords "games" "neural network" "adaptive search" "chemotaxis"))]) + (let-alist . + [(1 0 5) + ((emacs + (24 1))) + "Easily let-bind values of an assoc-list by their names" single + ((:url . "http://elpa.gnu.org/packages/let-alist.html") + (:keywords "extensions" "lisp"))]) + (lex . + [(1 1) + nil "Lexical analyser construction" tar + ((:url . "http://elpa.gnu.org/packages/lex.html"))]) + (lmc . + [(1 4) + ((emacs + (24)) + (cl-lib + (0 5))) + "Little Man Computer in Elisp" single + ((:url . "http://elpa.gnu.org/packages/lmc.html") + (:keywords))]) + (load-dir . + [(0 0 5) + ((cl-lib + (0 5))) + "Load all Emacs Lisp files in a given directory" single + ((:url . "http://elpa.gnu.org/packages/load-dir.html") + (:keywords "lisp" "files" "convenience"))]) + (load-relative . + [(1 3) + nil "relative file load (within a multi-file Emacs package)" single + ((:url . "http://github.com/rocky/emacs-load-relative") + (:keywords "internal"))]) + (loc-changes . + [(1 2) + nil "keep track of positions even after buffer changes" single + ((:url . "http://github.com/rocky/emacs-loc-changes") + (:keywords))]) + (loccur . + [(1 2 3) + ((cl-lib + (0))) + "Perform an occur-like folding in current buffer" single + ((:url . "https://github.com/fourier/loccur") + (:keywords "matching"))]) + (markchars . + [(0 2 0) + nil "Mark chars fitting certain characteristics" single + ((:url . "http://elpa.gnu.org/packages/markchars.html") + (:keywords))]) + (math-symbol-lists . + [(1 1) + nil "Lists of Unicode math symbols and latex commands" tar + ((:keywords "unicode" "symbols" "mathematics") + (:url . "https://github.com/vspinu/math-symbol-lists"))]) + (memory-usage . + [(0 2) + nil "Analyze the memory usage of Emacs in various ways" single + ((:url . "http://elpa.gnu.org/packages/memory-usage.html") + (:keywords "maint"))]) + (metar . + [(0 3) + ((cl-lib + (0 5))) + "Retrieve and decode METAR weather information" single + ((:url . "http://elpa.gnu.org/packages/metar.html") + (:keywords "comm"))]) + (midi-kbd . + [(0 2) + ((emacs + (25))) + "Create keyboard events from Midi input" single + ((:url . "http://elpa.gnu.org/packages/midi-kbd.html") + (:keywords "convenience" "hardware" "multimedia"))]) + (minibuffer-line . + [(0 1) + nil "Display status info in the minibuffer window" single + ((:url . "http://elpa.gnu.org/packages/minibuffer-line.html") + (:keywords))]) + (minimap . + [(1 2) + nil "Sidebar showing a \"mini-map\" of a buffer" single + ((:url . "http://elpa.gnu.org/packages/minimap.html") + (:keywords))]) + (multishell . + [(1 1 5) + nil "Easily use multiple shell buffers, local and remote." tar + ((:keywords "processes") + (:url . "https://github.com/kenmanheimer/EmacsMultishell"))]) + (muse . + [(3 20) + nil "Authoring and publishing tool for Emacs" tar + ((:keywords "hypermedia") + (:url . "http://mwolson.org/projects/EmacsMuse.html"))]) + (myers . + [(0 1) + ((emacs + (25))) + "Random-access singly-linked lists" single + ((:url . "http://elpa.gnu.org/packages/myers.html") + (:keywords "list" "containers"))]) + (nameless . + [(1 0 2) + ((emacs + (24 4))) + "Hide package namespace in your emacs-lisp code" single + ((:url . "https://github.com/Malabarba/nameless") + (:keywords "convenience" "lisp"))]) + (names . + [(20151201 0) + ((emacs + (24 1)) + (cl-lib + (0 5))) + "Namespaces for emacs-lisp. Avoid name clobbering without hiding symbols." tar + ((:keywords "extensions" "lisp") + (:url . "https://github.com/Malabarba/names"))]) + (nhexl-mode . + [(0 2) + ((emacs + (24)) + (cl-lib + (0 5))) + "Minor mode to edit files via hex-dump format" single + ((:url . "http://elpa.gnu.org/packages/nhexl-mode.html") + (:keywords "data"))]) + (nlinum . + [(1 7) + nil "Show line numbers in the margin" single + ((:url . "http://elpa.gnu.org/packages/nlinum.html") + (:keywords "convenience"))]) + (notes-mode . + [(1 30) + nil "Indexing system for on-line note-taking" tar + ((:url . "http://elpa.gnu.org/packages/notes-mode.html"))]) + (ntlm . + [(2 1 0) + nil "NTLM (NT LanManager) authentication support" single + ((:url . "http://elpa.gnu.org/packages/ntlm.html") + (:keywords "ntlm" "sasl" "comm"))]) + (num3-mode . + [(1 2) + nil "highlight groups of digits in long numbers" single + ((:url . "http://elpa.gnu.org/packages/num3-mode.html") + (:keywords "faces" "minor-mode"))]) + (oauth2 . + [(0 11) + nil "OAuth 2.0 Authorization Protocol" single + ((:url . "http://elpa.gnu.org/packages/oauth2.html") + (:keywords "comm"))]) + (omn-mode . + [(1 2) + nil "Support for OWL Manchester Notation" single + ((:url . "http://elpa.gnu.org/packages/omn-mode.html") + (:keywords))]) + (on-screen . + [(1 3 2) + ((cl-lib + (0))) + "guide your eyes while scrolling" single + ((:url . "https://github.com/michael-heerdegen/on-screen.el") + (:keywords "convenience"))]) + (org . + [(20171004) + nil "Outline-based notes management and organizer" tar nil]) + (org-edna . + [(1 0 -3 1) + ((emacs + (25 1)) + (seq + (2 19)) + (org + (9 0 5))) + "Extensible Dependencies 'N' Actions" tar + ((:keywords "convenience" "text" "org") + (:url . "https://savannah.nongnu.org/projects/org-edna-el/"))]) + (osc . + [(0 1) + nil "Open Sound Control protocol library" single + ((:url . "http://elpa.gnu.org/packages/osc.html") + (:keywords "comm" "processes" "multimedia"))]) + (other-frame-window . + [(1 0 4) + ((emacs + (24 4))) + "Minor mode to enable global prefix keys for other frame/window buffer placement" single + ((:url . "http://elpa.gnu.org/packages/other-frame-window.html") + (:keywords "frame" "window"))]) + (pabbrev . + [(4 2 1) + nil "Predictive abbreviation expansion" single + ((:url . "http://elpa.gnu.org/packages/pabbrev.html") + (:keywords))]) + (parsec . + [(0 1 3) + ((emacs + (24)) + (cl-lib + (0 5))) + "Parser combinator library" tar + ((:keywords "extensions") + (:url . "https://github.com/cute-jumper/parsec.el"))]) + (pinentry . + [(0 1) + nil "GnuPG Pinentry server implementation" single + ((:url . "http://elpa.gnu.org/packages/pinentry.html") + (:keywords "gnupg"))]) + (poker . + [(0 2) + nil "Texas hold 'em poker" single + ((:url . "http://elpa.gnu.org/packages/poker.html") + (:keywords "games"))]) + (psgml . + [(1 3 4) + nil "SGML-editing mode with parsing support" tar + ((:keywords "languages") + (:url . "http://elpa.gnu.org/packages/psgml.html"))]) + (python . + [(0 25 2) + ((emacs + (24 1)) + (cl-lib + (1 0))) + "Python's flying circus support for Emacs" single + ((:url . "https://github.com/fgallina/python.el") + (:keywords "languages"))]) + (quarter-plane . + [(0 1) + nil "Minor mode for quarter-plane style editing" single + ((:url . "http://elpa.gnu.org/packages/quarter-plane.html") + (:keywords "convenience" "wp"))]) + (queue . + [(0 2) + nil "Queue data structure" single + ((:url . "http://www.dr-qubit.org/emacs.php") + (:keywords "extensions" "data structures" "queue"))]) + (rainbow-mode . + [(0 13) + nil "Colorize color names in buffers" single + ((:url . "http://elpa.gnu.org/packages/rainbow-mode.html") + (:keywords "faces"))]) + (rcirc-color . + [(0 3) + nil "color nicks" single + ((:url . "http://elpa.gnu.org/packages/rcirc-color.html") + (:keywords "comm"))]) + (rcirc-menu . + [(1 1) + nil "A menu of all your rcirc connections" single + ((:url . "http://elpa.gnu.org/packages/rcirc-menu.html") + (:keywords "comm"))]) + (realgud . + [(1 4 4) + ((load-relative + (1 3)) + (loc-changes + (1 2)) + (test-simple + (1 3 0)) + (cl-lib + (0 5)) + (emacs + (24))) + "A modular front-end for interacting with external debuggers" tar + ((:keywords "gdb" "python" "perl" "go" "bash" "nodejs" "zsh" "bashdb" "zshdb" "remake" "make" "trepan" "perldb") + (:url . "http://github.com/realgud/realgud/"))]) + (register-list . + [(0 1) + nil "Interactively list/edit registers" single + ((:url . "http://elpa.gnu.org/packages/register-list.html") + (:keywords "register"))]) + (rich-minority . + [(1 0 1) + ((cl-lib + (0 5))) + "Clean-up and Beautify the list of minor-modes." single + ((:url . "https://github.com/Malabarba/rich-minority") + (:keywords "mode-line" "faces"))]) + (rnc-mode . + [(0 2) + nil "Emacs mode to edit Relax-NG Compact files" single + ((:url . "http://elpa.gnu.org/packages/rnc-mode.html") + (:keywords "xml" "relaxng"))]) + (rudel . + [(0 3 1) + ((emacs + (24)) + (cl-lib + (0 5)) + (cl-generic + (0 3))) + "A collaborative editing framework for Emacs" tar + ((:keywords "rudel" "collaboration") + (:url . "http://rudel.sourceforge.net/"))]) + (scroll-restore . + [(1 0) + nil "restore original position after scrolling" single + ((:url . "http://elpa.gnu.org/packages/scroll-restore.html") + (:keywords "scrolling"))]) + (sed-mode . + [(1 0) + nil "Major mode to edit sed scripts" single + ((:url . "http://elpa.gnu.org/packages/sed-mode.html") + (:keywords))]) + (seq . + [(2 20) + nil "Sequence manipulation functions" tar + ((:keywords "sequences") + (:url . "http://elpa.gnu.org/packages/seq.html"))]) + (shen-mode . + [(0 1) + nil "A major mode for editing shen source code" tar + ((:keywords "languages" "shen") + (:url . "http://elpa.gnu.org/packages/shen-mode.html"))]) + (sisu-mode . + [(7 1 8) + nil "Major mode for SiSU markup text" single + ((:url . "http://www.sisudoc.org/") + (:keywords "text" "syntax" "processes" "tools"))]) + (smart-yank . + [(0 1 1) + ((emacs + (24))) + "A different approach of yank pointer handling" single + ((:url . "http://elpa.gnu.org/packages/smart-yank.html") + (:keywords "convenience"))]) + (sml-mode . + [(6 7) + ((emacs + (24)) + (cl-lib + (0 5))) + "Major mode for editing (Standard) ML" single + ((:url . "http://elpa.gnu.org/packages/sml-mode.html") + (:keywords "sml"))]) + (soap-client . + [(3 1 3) + ((cl-lib + (0 6 1))) + "Access SOAP web services" tar + ((:keywords "soap" "web-services" "comm" "hypermedia") + (:url . "http://elpa.gnu.org/packages/soap-client.html"))]) + (sokoban . + [(1 4 6) + ((emacs + (23 1))) + "Implementation of Sokoban for Emacs." tar + ((:keywords "games") + (:url . "http://elpa.gnu.org/packages/sokoban.html"))]) + (sotlisp . + [(1 6 2) + ((emacs + (24 1))) + "Write lisp at the speed of thought." single + ((:url . "https://github.com/Malabarba/speed-of-thought-lisp") + (:keywords "convenience" "lisp"))]) + (spinner . + [(1 7 3) + nil "Add spinners and progress-bars to the mode-line for ongoing operations" single + ((:url . "https://github.com/Malabarba/spinner.el") + (:keywords "processes" "mode-line"))]) + (stream . + [(2 2 4) + ((emacs + (25))) + "Implementation of streams" tar + ((:keywords "stream" "laziness" "sequences") + (:url . "http://elpa.gnu.org/packages/stream.html"))]) + (svg . + [(0 1) + ((emacs + (25))) + "svg image creation functions" single + ((:url . "http://elpa.gnu.org/packages/svg.html") + (:keywords "image"))]) + (svg-clock . + [(1 0) + ((svg + (0 1)) + (emacs + (25 0))) + "Analog clock using Scalable Vector Graphics" single + ((:url . "http://elpa.gnu.org/packages/svg-clock.html") + (:keywords "demo" "svg" "clock"))]) + (tNFA . + [(0 1 1) + ((queue + (0 1))) + "Tagged non-deterministic finite-state automata" single + ((:url . "http://www.dr-qubit.org/emacs.php") + (:keywords "extensions" "matching" "data structures tnfa" "nfa" "dfa" "finite state automata" "automata" "regexp"))]) + (temp-buffer-browse . + [(1 5) + ((emacs + (24))) + "temp buffer browse mode" single + ((:url . "http://elpa.gnu.org/packages/temp-buffer-browse.html") + (:keywords "convenience"))]) + (test-simple . + [(1 3 0) + ((cl-lib + (0))) + "Simple Unit Test Framework for Emacs Lisp" single + ((:url . "http://github.com/rocky/emacs-test-simple") + (:keywords "unit-test"))]) + (timerfunctions . + [(1 4 2) + ((cl-lib + (0 5))) + "Enhanced versions of some timer.el functions" single + ((:url . "http://elpa.gnu.org/packages/timerfunctions.html") + (:keywords))]) + (tiny . + [(0 2 1) + nil "Quickly generate linear ranges in Emacs" tar + ((:keywords "convenience") + (:url . "https://github.com/abo-abo/tiny"))]) + (tramp-theme . + [(0 2) + ((emacs + (24 1))) + "Custom theme for remote buffers" single + ((:url . "http://elpa.gnu.org/packages/tramp-theme.html") + (:keywords "convenience" "faces"))]) + (transcribe . + [(1 5 2) + nil "Package for audio transcriptions" single + ((:url . "http://elpa.gnu.org/packages/transcribe.html") + (:keywords))]) + (trie . + [(0 4) + ((tNFA + (0 1 1)) + (heap + (0 3))) + "Trie data structure" single + ((:url . "http://www.dr-qubit.org/emacs.php") + (:keywords "extensions" "matching" "data structures trie" "ternary search tree" "tree" "completion" "regexp"))]) + (undo-tree . + [(0 6 5) + nil "Treat undo history as a tree" single + ((:url . "http://www.dr-qubit.org/emacs.php") + (:keywords "convenience" "files" "undo" "redo" "history" "tree"))]) + (uni-confusables . + [(0 1) + nil "Unicode confusables table" tar + ((:url . "http://elpa.gnu.org/packages/uni-confusables.html"))]) + (url-http-ntlm . + [(2 0 4) + ((cl-lib + (0 5)) + (ntlm + (2 1 0))) + "NTLM authentication for the url library" single + ((:url . "http://elpa.gnu.org/packages/url-http-ntlm.html") + (:keywords "comm" "data" "processes" "hypermedia"))]) + (validate . + [(1 0 4) + ((emacs + (24 1)) + (cl-lib + (0 5)) + (seq + (2 16))) + "Schema validation for Emacs-lisp" single + ((:url . "http://elpa.gnu.org/packages/validate.html") + (:keywords "lisp"))]) + (vdiff . + [(0 2 3) + ((emacs + (24 4)) + (hydra + (0 13 0))) + "A diff tool similar to vimdiff" single + ((:url . "https://github.com/justbur/emacs-vdiff") + (:keywords "diff"))]) + (vigenere . + [(1 0) + ((emacs + (25 1))) + "Run a vigenere cipher on a block of text ;" single + ((:url . "https://elpa.gnu.org/packages/vigenere.html") + (:keywords "data" "vigenere" "cipher"))]) + (vlf . + [(1 7) + nil "View Large Files" tar + ((:keywords "large files" "utilities") + (:url . "https://github.com/m00natic/vlfi"))]) + (w3 . + [(4 0 49) + nil "Fully customizable, largely undocumented web browser for Emacs" tar + ((:keywords "faces" "help" "comm" "news" "mail" "processes" "mouse" "hypermedia") + (:url . "http://elpa.gnu.org/packages/w3.html"))]) + (wcheck-mode . + [(2016 1 30) + nil "General interface for text checkers" single + ((:url . "https://github.com/tlikonen/wcheck-mode") + (:keywords "text" "spell" "check" "languages" "ispell"))]) + (wconf . + [(0 2 1) + ((emacs + (24 4))) + "Minimal window layout manager" single + ((:url . "https://github.com/ilohmar/wconf") + (:keywords "windows" "frames" "layout"))]) + (web-server . + [(0 1 1) + ((emacs + (24 3))) + "Emacs Web Server" tar + ((:keywords "http" "server" "network") + (:url . "https://github.com/eschulte/emacs-web-server"))]) + (websocket . + [(1 8) + ((cl-lib + (0 5))) + "Emacs WebSocket client and server" tar + ((:keywords "communication" "websocket" "server") + (:url . "http://elpa.gnu.org/packages/websocket.html"))]) + (which-key . + [(3 0 2) + ((emacs + (24 4))) + "Display available keybindings in popup" tar + ((:url . "https://github.com/justbur/emacs-which-key"))]) + (windresize . + [(0 1) + nil "Resize windows interactively" single + ((:url . "http://elpa.gnu.org/packages/windresize.html") + (:keywords "window"))]) + (wisi . + [(1 1 6) + ((cl-lib + (0 4)) + (emacs + (24 3))) + "Utilities for implementing an indentation/navigation engine using a generalized LALR parser" tar + ((:keywords "parser" "indentation" "navigation") + (:url . "http://www.nongnu.org/ada-mode/wisi/wisi.html"))]) + (wpuzzle . + [(1 1) + nil "find as many word in a given time" single + ((:url . "http://elpa.gnu.org/packages/wpuzzle.html") + (:keywords))]) + (xclip . + [(1 3) + nil "use xclip to copy&paste" single + ((:url . "http://elpa.gnu.org/packages/xclip.html") + (:keywords "convenience" "tools"))]) + (xelb . + [(0 12) + ((emacs + (24 4)) + (cl-generic + (0 2))) + "X protocol Emacs Lisp Binding" tar + ((:keywords "unix") + (:url . "https://github.com/ch11ng/xelb"))]) + (xpm . + [(1 0 4) + nil "edit XPM images" tar + ((:keywords "multimedia" "xpm") + (:url . "http://www.gnuvola.org/software/xpm/"))]) + (yasnippet . + [(0 12 2) + ((cl-lib + (0 5))) + "Yet another snippet extension for Emacs." tar + ((:keywords "convenience" "emulation") + (:url . "http://github.com/joaotavora/yasnippet"))]) + (ztree . + [(1 0 5) + ((cl-lib + (0))) + "Text mode directory tree" tar + ((:keywords "files" "tools") + (:url . "https://github.com/fourier/ztree"))])) diff --git a/elpa/archives/gnu/archive-contents.signed b/elpa/archives/gnu/archive-contents.signed new file mode 100644 index 0000000..6a92838 --- /dev/null +++ b/elpa/archives/gnu/archive-contents.signed @@ -0,0 +1 @@ +Good signature from 474F05837FBDEF9B GNU ELPA Signing Agent (trust undefined) created at 2017-10-05T11:10:02+0200 using DSA \ No newline at end of file diff --git a/elpa/gnupg/pubring.gpg b/elpa/gnupg/pubring.gpg new file mode 100644 index 0000000..e76e685 Binary files /dev/null and b/elpa/gnupg/pubring.gpg differ diff --git a/elpa/gnupg/secring.gpg b/elpa/gnupg/secring.gpg new file mode 100644 index 0000000..e69de29 diff --git a/elpa/gnupg/trustdb.gpg b/elpa/gnupg/trustdb.gpg new file mode 100644 index 0000000..1a45757 Binary files /dev/null and b/elpa/gnupg/trustdb.gpg differ diff --git a/elpa/let-alist-1.0.5.signed b/elpa/let-alist-1.0.5.signed new file mode 100644 index 0000000..8d89df9 --- /dev/null +++ b/elpa/let-alist-1.0.5.signed @@ -0,0 +1 @@ +Good signature from 474F05837FBDEF9B GNU ELPA Signing Agent (trust undefined) created at 2017-02-01T11:05:02+0100 using DSA \ No newline at end of file diff --git a/elpa/let-alist-1.0.5/let-alist-autoloads.el b/elpa/let-alist-1.0.5/let-alist-autoloads.el new file mode 100644 index 0000000..37bc69c --- /dev/null +++ b/elpa/let-alist-1.0.5/let-alist-autoloads.el @@ -0,0 +1,50 @@ +;;; let-alist-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) + +;;;### (autoloads nil "let-alist" "let-alist.el" (23053 39403 444445 +;;;;;; 274000)) +;;; Generated autoloads from let-alist.el + +(autoload 'let-alist "let-alist" "\ +Let-bind dotted symbols to their cdrs in ALIST and execute BODY. +Dotted symbol is any symbol starting with a `.'. Only those present +in BODY are let-bound and this search is done at compile time. + +For instance, the following code + + (let-alist alist + (if (and .title .body) + .body + .site + .site.contents)) + +essentially expands to + + (let ((.title (cdr (assq \\='title alist))) + (.body (cdr (assq \\='body alist))) + (.site (cdr (assq \\='site alist))) + (.site.contents (cdr (assq \\='contents (cdr (assq \\='site alist)))))) + (if (and .title .body) + .body + .site + .site.contents)) + +If you nest `let-alist' invocations, the inner one can't access +the variables of the outer one. You can, however, access alists +inside the original alist by using dots inside the symbol, as +displayed in the example above. + +\(fn ALIST &rest BODY)" nil t) + +(put 'let-alist 'lisp-indent-function '1) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; let-alist-autoloads.el ends here diff --git a/elpa/let-alist-1.0.5/let-alist-pkg.el b/elpa/let-alist-1.0.5/let-alist-pkg.el new file mode 100644 index 0000000..247d8c9 --- /dev/null +++ b/elpa/let-alist-1.0.5/let-alist-pkg.el @@ -0,0 +1 @@ +(define-package "let-alist" "1.0.5" "Easily let-bind values of an assoc-list by their names" '((emacs "24.1")) :url "http://elpa.gnu.org/packages/let-alist.html" :keywords '("extensions" "lisp")) diff --git a/elpa/let-alist-1.0.5/let-alist.el b/elpa/let-alist-1.0.5/let-alist.el new file mode 100644 index 0000000..43973c2 --- /dev/null +++ b/elpa/let-alist-1.0.5/let-alist.el @@ -0,0 +1,182 @@ +;;; let-alist.el --- Easily let-bind values of an assoc-list by their names -*- lexical-binding: t; -*- + +;; Copyright (C) 2014-2017 Free Software Foundation, Inc. + +;; Author: Artur Malabarba +;; Package-Requires: ((emacs "24.1")) +;; Version: 1.0.5 +;; Keywords: extensions lisp +;; Prefix: let-alist +;; Separator: - + +;; This is an Elpa :core package. Don't use functionality that is not +;; compatible with Emacs 24.1. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;; This package offers a single macro, `let-alist'. This macro takes a +;; first argument (whose value must be an alist) and a body. +;; +;; The macro expands to a let form containing body, where each dotted +;; symbol inside body is let-bound to their cdrs in the alist. Dotted +;; symbol is any symbol starting with a `.'. Only those present in +;; the body are let-bound and this search is done at compile time. +;; +;; For instance, the following code +;; +;; (let-alist alist +;; (if (and .title .body) +;; .body +;; .site +;; .site.contents)) +;; +;; essentially expands to +;; +;; (let ((.title (cdr (assq 'title alist))) +;; (.body (cdr (assq 'body alist))) +;; (.site (cdr (assq 'site alist))) +;; (.site.contents (cdr (assq 'contents (cdr (assq 'site alist)))))) +;; (if (and .title .body) +;; .body +;; .site +;; .site.contents)) +;; +;; If you nest `let-alist' invocations, the inner one can't access +;; the variables of the outer one. You can, however, access alists +;; inside the original alist by using dots inside the symbol, as +;; displayed in the example above by the `.site.contents'. +;; +;;; Code: + + +(defun let-alist--deep-dot-search (data) + "Return alist of symbols inside DATA that start with a `.'. +Perform a deep search and return an alist where each car is the +symbol, and each cdr is the same symbol without the `.'." + (cond + ((symbolp data) + (let ((name (symbol-name data))) + (when (string-match "\\`\\." name) + ;; Return the cons cell inside a list, so it can be appended + ;; with other results in the clause below. + (list (cons data (intern (replace-match "" nil nil name))))))) + ((not (consp data)) nil) + ((eq (car data) 'let-alist) + ;; For nested ‘let-alist’ forms, ignore symbols appearing in the + ;; inner body because they don’t refer to the alist currently + ;; being processed. See Bug#24641. + (let-alist--deep-dot-search (cadr data))) + (t (append (let-alist--deep-dot-search (car data)) + (let-alist--deep-dot-search (cdr data)))))) + +(defun let-alist--access-sexp (symbol variable) + "Return a sexp used to access SYMBOL inside VARIABLE." + (let* ((clean (let-alist--remove-dot symbol)) + (name (symbol-name clean))) + (if (string-match "\\`\\." name) + clean + (let-alist--list-to-sexp + (mapcar #'intern (nreverse (split-string name "\\."))) + variable)))) + +(defun let-alist--list-to-sexp (list var) + "Turn symbols LIST into recursive calls to `cdr' `assq' on VAR." + `(cdr (assq ',(car list) + ,(if (cdr list) (let-alist--list-to-sexp (cdr list) var) + var)))) + +(defun let-alist--remove-dot (symbol) + "Return SYMBOL, sans an initial dot." + (let ((name (symbol-name symbol))) + (if (string-match "\\`\\." name) + (intern (replace-match "" nil nil name)) + symbol))) + + +;;; The actual macro. +;;;###autoload +(defmacro let-alist (alist &rest body) + "Let-bind dotted symbols to their cdrs in ALIST and execute BODY. +Dotted symbol is any symbol starting with a `.'. Only those present +in BODY are let-bound and this search is done at compile time. + +For instance, the following code + + (let-alist alist + (if (and .title .body) + .body + .site + .site.contents)) + +essentially expands to + + (let ((.title (cdr (assq \\='title alist))) + (.body (cdr (assq \\='body alist))) + (.site (cdr (assq \\='site alist))) + (.site.contents (cdr (assq \\='contents (cdr (assq \\='site alist)))))) + (if (and .title .body) + .body + .site + .site.contents)) + +If you nest `let-alist' invocations, the inner one can't access +the variables of the outer one. You can, however, access alists +inside the original alist by using dots inside the symbol, as +displayed in the example above." + (declare (indent 1) (debug t)) + (let ((var (make-symbol "alist"))) + `(let ((,var ,alist)) + (let ,(mapcar (lambda (x) `(,(car x) ,(let-alist--access-sexp (car x) var))) + (delete-dups (let-alist--deep-dot-search body))) + ,@body)))) + +;;;; ChangeLog: + +;; 2015-12-01 Artur Malabarba +;; +;; packages/let-alist: Define it as a :core package +;; +;; 2015-06-11 Artur Malabarba +;; +;; * let-alist (let-alist--deep-dot-search): Fix cons +;; +;; 2015-03-07 Artur Malabarba +;; +;; let-alist: Update copyright +;; +;; 2014-12-22 Artur Malabarba +;; +;; packages/let-alist: Use `make-symbol' instead of `gensym'. +;; +;; 2014-12-20 Artur Malabarba +;; +;; packages/let-alist: Enable access to deeper alists +;; +;; 2014-12-14 Artur Malabarba +;; +;; let-alist.el: Add lexical binding. Version bump. +;; +;; 2014-12-11 Artur Malabarba +;; +;; let-alist: New package +;; + + +(provide 'let-alist) + +;;; let-alist.el ends here diff --git a/elpa/websocket-1.8.signed b/elpa/websocket-1.8.signed new file mode 100644 index 0000000..ab75e0e --- /dev/null +++ b/elpa/websocket-1.8.signed @@ -0,0 +1 @@ +Good signature from 474F05837FBDEF9B GNU ELPA Signing Agent (trust undefined) created at 2017-06-12T11:10:03+0200 using DSA \ No newline at end of file diff --git a/elpa/websocket-1.8/COPYING b/elpa/websocket-1.8/COPYING new file mode 100644 index 0000000..ecbc059 --- /dev/null +++ b/elpa/websocket-1.8/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. \ No newline at end of file diff --git a/elpa/websocket-1.8/ChangeLog b/elpa/websocket-1.8/ChangeLog new file mode 100644 index 0000000..ca8f6f5 --- /dev/null +++ b/elpa/websocket-1.8/ChangeLog @@ -0,0 +1,119 @@ +2017-06-11 Andrew Hyatt + + Update to emacs-websocket version 1.8. + + * websocket.el (websocket-mask): Mask multibyte characters correctly. + * websocket.el (websocket-server): Don't ask to terminate the + connection. + * websocket-functional-test.el: Test out multibyte characters. + * websocket-functional-test.el: Disable trust checking for echo server + connection. + +2016-07-11 Paul Eggert + + Fix some quoting problems in doc strings + + Most of these are minor issues involving, e.g., quoting `like this' + instead of 'like this'. A few involve escaping ` and ' with a preceding + \= when the characters should not be turned into curved single quotes. + +2016-05-10 Stefan Monnier + + * websocket/websocket.el (websocket-server-accept): Mark arg as unused + + * websocket/websocket-functional-test.el: Fix compilation warnings. + +2016-05-09 Andrew Hyatt + + Version 1.6, mostly fixes for fragmented headers. + + * websocket.el (websocket-verify-response-code, websocket-outer-filter): + Fix handling of fragmented headers. + * websocket.el (websocket-server): Accept host for listening on. + * websocket-functional-test.el: Stop stopping the listener process on + Windows. + +2016-01-24 Stefan Monnier + + Fix maintainer address + +2015-07-19 Andrew Hyatt + + Add ability to handle cookies. + + * websocket.el (websocket-open, websocket-process-headers, + websocket-out-filter, websocket-create-headers): Add ability to set + and accept cookies, using the url-cookie library. Also make sure the + port is included in the Host header. + +2015-04-03 Andrew Hyatt + + Version 1.4, fix for ping/pong & 32-bit emacs. + + * websocket.el (websocket-encode-frame, websocket-read-frame, + websocket-process-frame, websocket-check) Fixes incorrect handling of + ping/pong messages in websockets. + (websocket-to-bytes) Fixes error computing low-bytes in 32-bit emacs. + +2014-08-23 Andrew Hyatt + + Upgrade to version 1.3. + + * websocket.el: (websocket-version):Update to 1.3 + (websocket-close): Remove unnecessary call to process-buffer. + (websocket-close): Remove use of buffers in connections. + (websocket-open): Remove use of buffers in connections. + (websocket-open): Throw clear error when connection cannot be made. + (websocket-create-headers): Remove unnecessary Origin header. + +2013-12-14 Andrew Hyatt + + Remove the ERT testing file, which had too many FSF-unsigned changes. + + This brings this package into FSF compliance. + + * README.org: Mention the fact that the ERT tests are in the github + repository. + + * websocket-test.el: Removed. + +2013-09-21 Andrew Hyatt + + websocket.el: Set version to 1.2, after last set of server fixes. + +2013-09-15 Andrew Hyatt + + 2013-09-15 Andrew Hyatt + + * websocket.el (websocket-mask-frames, websocket-encode-frame, + websocket, websocket-send): Get rid of + `websocket-mask-frames' variable, which was a mistake, and + make masking mandatory for clients and forbidden for + servers. + * websocket-test.el (websocket-encode-frame, + websocket-outer-filter): Alter tests to pass new argument + for `websocket-encode-frame'. + + * websocket.el (websocket-close, websocket-open, + websocket-server-accept): Only call the on-close callback on + process state change if the process is now closed or + similar, and always call the on-close callback from + `websocket-close' + * websocket-test.el (websocket-close): Add an on-close callback + which the `websocket-close' method now expects. + + * magit-functiona-test.el: Assert on ready-state, and increase + the sleep time for the wss test. + +2013-08-02 Stefan Monnier + + * packages/websocket/websocket.el: Fix version number. + +2013-08-01 Stefan Monnier + + * packages/websocket: Cleanup copyright and code. + +2013-08-01 Stefan Monnier + + Add websocket git revno bc5c2a2ee2b993a18e8e23ed725829d403508753. + diff --git a/elpa/websocket-1.8/README.org b/elpa/websocket-1.8/README.org new file mode 100644 index 0000000..db5abba --- /dev/null +++ b/elpa/websocket-1.8/README.org @@ -0,0 +1,35 @@ +* Description +This is a elisp library for websocket clients to talk to websocket +servers, and for websocket servers to accept connections from +websocket clients. This library is designed to be used by other +library writers, to write apps that use websockets, and is not useful +by itself. + +An example of how to use the library is in the +[[https://github.com/ahyatt/emacs-websocket/blob/master/websocket-functional-test.el][websocket-functional-test.el]] file. + +This library is compatible with emacs 23 and 24, although only emacs +24 support secure websockets. + +NOTE: Due to FSF attribution restrictions, ERT tests are only not +present in the emacs ELPA repository. They can only be found in the +github repository at https://github.com/ahyatt/emacs-websocket/. + +* Version release checklist + +Each version that is released should be checked with this checklist: + +- [ ] All ert test passing (see note above on ERT tests) +- [ ] Functional test passing on emacs 23 and 24 +- [ ] websocket.el byte compiling cleanly. + +* Existing clients: + +- [[https://github.com/tkf/emacs-ipython-notebook][Emacs IPython Notebook]] +- [[https://github.com/syohex/emacs-realtime-markdown-viewer][Emacs Realtime Markdown Viewer]] +- [[https://github.com/jscheid/kite][Kite]] + +If you are using this module for your own emacs package, please let me +know by editing this file, adding your project, and sending a pull +request to this repository. + diff --git a/elpa/websocket-1.8/testserver.py b/elpa/websocket-1.8/testserver.py new file mode 100644 index 0000000..5cfcb96 --- /dev/null +++ b/elpa/websocket-1.8/testserver.py @@ -0,0 +1,34 @@ +import logging +import tornado +import tornado.web +from tornado import httpserver +from tornado import ioloop +from tornado import websocket + + +class EchoWebSocket(websocket.WebSocketHandler): + + def open(self): + logging.info("OPEN") + + def on_message(self, message): + logging.info(u"ON_MESSAGE: {0}".format(message)) + self.write_message(u"You said: {0}".format(message)) + + def on_close(self): + logging.info("ON_CLOSE") + + def allow_draft76(self): + return False + + +if __name__ == "__main__": + import tornado.options + tornado.options.parse_command_line() + application = tornado.web.Application([ + (r"/", EchoWebSocket), + ]) + server = httpserver.HTTPServer(application) + server.listen(9999) + logging.info("STARTED: Server start listening") + ioloop.IOLoop.instance().start() diff --git a/elpa/websocket-1.8/websocket-autoloads.el b/elpa/websocket-1.8/websocket-autoloads.el new file mode 100644 index 0000000..b2bc340 --- /dev/null +++ b/elpa/websocket-1.8/websocket-autoloads.el @@ -0,0 +1,16 @@ +;;; websocket-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) + +;;;### (autoloads nil nil ("websocket-functional-test.el" "websocket-pkg.el" +;;;;;; "websocket.el") (23053 39388 567397 365000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; websocket-autoloads.el ends here diff --git a/elpa/websocket-1.8/websocket-functional-test.el b/elpa/websocket-1.8/websocket-functional-test.el new file mode 100644 index 0000000..80eb004 --- /dev/null +++ b/elpa/websocket-1.8/websocket-functional-test.el @@ -0,0 +1,162 @@ +;;; websocket-functional-test.el --- Simple functional testing + +;; Copyright (c) 2013, 2016 Free Software Foundation, Inc. + +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 3 of the +;; License, or (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;; Usage: emacs -batch -Q -L . -l websocket-functional-test.el +;; +;; Note: this functional tests requires that you have python with the +;; Tornado web server. See http://www.tornadoweb.org/en/stable/ for +;; information on aquiring. + +(require 'tls) ;; tests a particular bug we had on emacs 23 +(setq debug-on-error t) +(require 'websocket) +(eval-when-compile (require 'cl)) + +;;;;;;;;;;;;;;;;;;;;;;; +;; Local server test ;; +;;;;;;;;;;;;;;;;;;;;;;; + +(message "Testing with local server") + +(setq websocket-debug t) + +(defvar wstest-server-buffer (get-buffer-create "*wstest-server*")) +(defvar wstest-server-name "wstest-server") +(defvar wstest-server-proc + (start-process wstest-server-name wstest-server-buffer + "python" "testserver.py" "--log_to_stderr" "--logging=debug")) +(sleep-for 1) + +(defvar wstest-msgs nil) +(defvar wstest-closed nil) + +(message "Opening the websocket") + +(defvar wstest-ws + (websocket-open + "ws://127.0.0.1:9999" + :on-message (lambda (_websocket frame) + (push (websocket-frame-text frame) wstest-msgs) + (message "ws frame: %S" (websocket-frame-text frame)) + (error "Test error (expected)")) + :on-close (lambda (_websocket) (setq wstest-closed t)))) + +(defun wstest-pop-to-debug () + "Open websocket log buffer. Not used in testing. Just for debugging." + (interactive) + (pop-to-buffer (websocket-get-debug-buffer-create wstest-ws))) + +(sleep-for 0.1) +(assert (websocket-openp wstest-ws)) + +(assert (null wstest-msgs)) + +(websocket-send-text wstest-ws "你好") + +(sleep-for 0.1) +(assert (equal (car wstest-msgs) "You said: 你好")) +(setf (websocket-on-error wstest-ws) (lambda (_ws _type _err))) +(websocket-send-text wstest-ws "Hi after error!") +(sleep-for 0.1) +(assert (equal (car wstest-msgs) "You said: Hi after error!")) + +(websocket-close wstest-ws) +(assert (null (websocket-openp wstest-ws))) + +(if (not (eq system-type 'windows-nt)) + ; Windows doesn't have support for the SIGSTP signal, so we'll just kill + ; the process. + (stop-process wstest-server-proc)) +(kill-process wstest-server-proc) + +;; Make sure the processes are closed. This happens asynchronously, +;; so let's wait for it. +(sleep-for 1) +(assert (null (process-list)) t) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Remote server test, with wss ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; echo.websocket.org has an untrusted certificate, for the test to +;; proceed, we need to disable trust checking. +(setq tls-checktrust nil) + +(when (>= (string-to-number (substring emacs-version 0 2)) 24) + (message "Testing with wss://echo.websocket.org") + (when (eq system-type 'windows-nt) + (message "Windows users must have gnutls DLLs in the emacs bin directory.")) + (setq wstest-ws + (websocket-open + "wss://echo.websocket.org" + :on-open (lambda (_websocket) + (message "Websocket opened")) + :on-message (lambda (_websocket frame) + (push (websocket-frame-text frame) wstest-msgs) + (message "ws frame: %S" (websocket-frame-text frame))) + :on-close (lambda (_websocket) + (message "Websocket closed") + (setq wstest-closed t))) + wstest-msgs nil) + (sleep-for 0.3) + (assert (websocket-openp wstest-ws)) + (assert (eq 'open (websocket-ready-state wstest-ws))) + (assert (null wstest-msgs)) + (websocket-send-text wstest-ws "Hi!") + (sleep-for 1) + (assert (equal (car wstest-msgs) "Hi!")) + (websocket-close wstest-ws)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Local client and server ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(message "Testing with emacs websocket server.") +(message "If this does not pass, make sure your firewall allows the connection.") +(setq wstest-closed nil) +(let ((server-conn (websocket-server + 9998 + :host 'local + :on-message (lambda (ws frame) + (message "Server received text!") + (websocket-send-text + ws (websocket-frame-text frame))) + :on-open (lambda (_websocket) "Client connection opened!") + :on-close (lambda (_websocket) + (setq wstest-closed t))))) + (setq wstest-msgs nil + wstest-ws + (websocket-open + "ws://localhost:9998" + :on-message (lambda (_websocket frame) + (message "ws frame: %S" (websocket-frame-text frame)) + (push + (websocket-frame-text frame) wstest-msgs)))) + + (assert (websocket-openp wstest-ws)) + (websocket-send-text wstest-ws "你好") + (sleep-for 0.3) + (assert (equal (car wstest-msgs) "你好")) + (websocket-server-close server-conn)) +(assert wstest-closed) +(websocket-close wstest-ws) + +(sleep-for 1) +(assert (null (process-list)) t) +(message "\nAll tests passed!\n") diff --git a/elpa/websocket-1.8/websocket-pkg.el b/elpa/websocket-1.8/websocket-pkg.el new file mode 100644 index 0000000..347295b --- /dev/null +++ b/elpa/websocket-1.8/websocket-pkg.el @@ -0,0 +1,2 @@ +;; Generated package description from websocket.el +(define-package "websocket" "1.8" "Emacs WebSocket client and server" 'nil :url "http://elpa.gnu.org/packages/websocket.html" :keywords '("communication" "websocket" "server")) diff --git a/elpa/websocket-1.8/websocket.el b/elpa/websocket-1.8/websocket.el new file mode 100644 index 0000000..3784a30 --- /dev/null +++ b/elpa/websocket-1.8/websocket.el @@ -0,0 +1,1046 @@ +;;; websocket.el --- Emacs WebSocket client and server + +;; Copyright (c) 2013, 2016 Free Software Foundation, Inc. + +;; Author: Andrew Hyatt +;; Keywords: Communication, Websocket, Server +;; Version: 1.8 +;; +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 3 of the +;; License, or (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: +;; This implements RFC 6455, which can be found at +;; http://tools.ietf.org/html/rfc6455. +;; +;; This library contains code to connect Emacs as a client to a +;; websocket server, and for Emacs to act as a server for websocket +;; connections. +;; +;; Websockets clients are created by calling `websocket-open', which +;; returns a `websocket' struct. Users of this library use the +;; websocket struct, and can call methods `websocket-send-text', which +;; sends text over the websocket, or `websocket-send', which sends a +;; `websocket-frame' struct, enabling finer control of what is sent. +;; A callback is passed to `websocket-open' that will retrieve +;; websocket frames called from the websocket. Websockets are +;; eventually closed with `websocket-close'. +;; +;; Server functionality is similar. A server is started with +;; `websocket-server' called with a port and the callbacks to use, +;; which returns a process. The process can later be closed with +;; `websocket-server-close'. A `websocket' struct is also created +;; for every connection, and is exposed through the callbacks. + +(require 'bindat) +(require 'url-parse) +(require 'url-cookie) +(eval-when-compile (require 'cl)) + +;;; Code: + +(defstruct (websocket + (:constructor nil) + (:constructor websocket-inner-create)) + "A websocket structure. +This follows the W3C Websocket API, except translated to elisp +idioms. The API is implemented in both the websocket struct and +additional methods. Due to how defstruct slots are accessed, all +API methods are prefixed with \"websocket-\" and take a websocket +as an argument, so the distrinction between the struct API and +the additional helper APIs are not visible to the caller. + +A websocket struct is created with `websocket-open'. + +`ready-state' contains one of `connecting', `open', or +`closed', depending on the state of the websocket. + +The W3C API \"bufferedAmount\" call is not currently implemented, +since there is no elisp API to get the buffered amount from the +subprocess. There may, in fact, be output data buffered, +however, when the `on-message' or `on-close' callbacks are +called. + +`on-open', `on-message', `on-close', and `on-error' are described +in `websocket-open'. + +The `negotiated-extensions' slot lists the extensions accepted by +both the client and server, and `negotiated-protocols' does the +same for the protocols. +" + ;; API + (ready-state 'connecting) + client-data + on-open + on-message + on-close + on-error + negotiated-protocols + negotiated-extensions + (server-p nil :read-only t) + + ;; Other data - clients should not have to access this. + (url (assert nil) :read-only t) + (protocols nil :read-only t) + (extensions nil :read-only t) + (conn (assert nil) :read-only t) + ;; Only populated for servers, this is the server connection. + server-conn + accept-string + (inflight-input nil)) + +(defvar websocket-version "1.5" + "Version numbers of this version of websocket.el.") + +(defvar websocket-debug nil + "Set to true to output debugging info to a per-websocket buffer. +The buffer is ` *websocket URL debug*' where URL is the +URL of the connection.") + +(defconst websocket-guid "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + "The websocket GUID as defined in RFC 6455. +Do not change unless the RFC changes.") + +(defvar websocket-callback-debug-on-error nil + "If true, when an error happens in a client callback, invoke the debugger. +Having this on can cause issues with missing frames if the debugger is +exited by quitting instead of continuing, so it's best to have this set +to nil unless it is especially needed.") + +(defmacro websocket-document-function (function docstring) + "Document FUNCTION with DOCSTRING. Use this for defstruct accessor etc." + (declare (indent defun) + (doc-string 2)) + `(put ',function 'function-documentation ,docstring)) + +(websocket-document-function websocket-on-open + "Accessor for websocket on-open callback. +See `websocket-open' for details. + +\(fn WEBSOCKET)") + +(websocket-document-function websocket-on-message + "Accessor for websocket on-message callback. +See `websocket-open' for details. + +\(fn WEBSOCKET)") + +(websocket-document-function websocket-on-close + "Accessor for websocket on-close callback. +See `websocket-open' for details. + +\(fn WEBSOCKET)") + +(websocket-document-function websocket-on-error + "Accessor for websocket on-error callback. +See `websocket-open' for details. + +\(fn WEBSOCKET)") + +(defun websocket-genbytes (nbytes) + "Generate NBYTES random bytes." + (let ((s (make-string nbytes ?\s))) + (dotimes (i nbytes) + (aset s i (random 256))) + s)) + +(defun websocket-try-callback (websocket-callback callback-type websocket + &rest rest) + "Invoke function WEBSOCKET-CALLBACK with WEBSOCKET and REST args. +If an error happens, it is handled according to +`websocket-callback-debug-on-error'." + ;; This looks like it should be able to done more efficiently, but + ;; I'm not sure that's the case. We can't do it as a macro, since + ;; we want it to change whenever websocket-callback-debug-on-error + ;; changes. + (let ((args rest) + (debug-on-error websocket-callback-debug-on-error)) + (push websocket args) + (if websocket-callback-debug-on-error + (condition-case err + (apply (funcall websocket-callback websocket) args) + ((debug error) (funcall (websocket-on-error websocket) + websocket callback-type err))) + (condition-case err + (apply (funcall websocket-callback websocket) args) + (error (funcall (websocket-on-error websocket) websocket + callback-type err)))))) + +(defun websocket-genkey () + "Generate a key suitable for the websocket handshake." + (base64-encode-string (websocket-genbytes 16))) + +(defun websocket-calculate-accept (key) + "Calculate the expect value of the accept header. +This is based on the KEY from the Sec-WebSocket-Key header." + (base64-encode-string + (sha1 (concat key websocket-guid) nil nil t))) + +(defun websocket-get-bytes (s n) + "From string S, retrieve the value of N bytes. +Return the value as an unsigned integer. The value N must be a +power of 2, up to 8. + +We support getting frames up to 536870911 bytes (2^29 - 1), +approximately 537M long." + (if (= n 8) + (let* ((32-bit-parts + (bindat-get-field (bindat-unpack '((:val vec 2 u32)) s) :val)) + (cval + (logior (lsh (aref 32-bit-parts 0) 32) (aref 32-bit-parts 1)))) + (if (and (= (aref 32-bit-parts 0) 0) + (= (lsh (aref 32-bit-parts 1) -29) 0)) + cval + (signal 'websocket-unparseable-frame + "Frame value found too large to parse!"))) + ;; n is not 8 + (bindat-get-field + (condition-case _ + (bindat-unpack + `((:val + ,(cond ((= n 1) 'u8) + ((= n 2) 'u16) + ((= n 4) 'u32) + ;; This is an error with the library, + ;; not a user-facing, meaningful error. + (t (error + "websocket-get-bytes: Unknown N: %s" n))))) + s) + (args-out-of-range (signal 'websocket-unparseable-frame + (format "Frame unexpectedly shortly: %s" s)))) + :val))) + +(defun websocket-to-bytes (val nbytes) + "Encode the integer VAL in NBYTES of data. +NBYTES much be a power of 2, up to 8. + +This supports encoding values up to 536870911 bytes (2^29 - 1), +approximately 537M long." + (when (and (< nbytes 8) + (> val (expt 2 (* 8 nbytes)))) + ;; not a user-facing error, this must be caused from an error in + ;; this library + (error "websocket-to-bytes: Value %d could not be expressed in %d bytes" + val nbytes)) + (if (= nbytes 8) + (progn + (let ((hi-32bits (lsh val -32)) + ;; Test for systems that don't have > 32 bits, and + ;; for those systems just return the value. + (low-32bits (if (= 0 (expt 2 32)) + val + (logand #xffffffff val)))) + (when (or (> hi-32bits 0) (> (lsh low-32bits -29) 0)) + (signal 'websocket-frame-too-large val)) + (bindat-pack `((:val vec 2 u32)) + `((:val . [,hi-32bits ,low-32bits]))))) + (bindat-pack + `((:val ,(cond ((= nbytes 1) 'u8) + ((= nbytes 2) 'u16) + ((= nbytes 4) 'u32) + ;; Library error, not system error + (t (error "websocket-to-bytes: Unknown NBYTES: %s" nbytes))))) + `((:val . ,val))))) + +(defun websocket-get-opcode (s) + "Retrieve the opcode from first byte of string S." + (websocket-ensure-length s 1) + (let ((opcode (logand #xf (websocket-get-bytes s 1)))) + (cond ((= opcode 0) 'continuation) + ((= opcode 1) 'text) + ((= opcode 2) 'binary) + ((= opcode 8) 'close) + ((= opcode 9) 'ping) + ((= opcode 10) 'pong)))) + +(defun websocket-get-payload-len (s) + "Parse out the payload length from the string S. +We start at position 0, and return a cons of the payload length and how +many bytes were consumed from the string." + (websocket-ensure-length s 1) + (let* ((initial-val (logand 127 (websocket-get-bytes s 1)))) + (cond ((= initial-val 127) + (websocket-ensure-length s 9) + (cons (websocket-get-bytes (substring s 1) 8) 9)) + ((= initial-val 126) + (websocket-ensure-length s 3) + (cons (websocket-get-bytes (substring s 1) 2) 3)) + (t (cons initial-val 1))))) + +(defstruct websocket-frame opcode payload length completep) + +(defun websocket-frame-text (frame) + "Given FRAME, return the payload as a utf-8 encoded string." + (assert (websocket-frame-p frame)) + (decode-coding-string (websocket-frame-payload frame) 'utf-8)) + +(defun websocket-mask (key data) + "Using string KEY, mask string DATA according to the RFC. +This is used to both mask and unmask data." + ;; If we don't make the string unibyte here, a string of bytes that should be + ;; interpreted as a unibyte string will instead be interpreted as a multibyte + ;; string of the same length (for example, 6 multibyte chars for 你好 instead + ;; of the correct 6 unibyte chars, which would convert into 2 multibyte + ;; chars). + (string-make-unibyte (apply + 'string + (loop for b across data + for i from 0 to (length data) + collect + (logxor (websocket-get-bytes (substring key (mod i 4)) 1) b))))) + +(defun websocket-ensure-length (s n) + "Ensure the string S has at most N bytes. +Otherwise we throw the error `websocket-incomplete-frame'." + (when (< (length s) n) + (throw 'websocket-incomplete-frame nil))) + +(defun websocket-encode-frame (frame should-mask) + "Encode the FRAME struct to the binary representation. +We mask the frame or not, depending on SHOULD-MASK." + (let* ((opcode (websocket-frame-opcode frame)) + (payload (websocket-frame-payload frame)) + (fin (websocket-frame-completep frame)) + (payloadp (and payload + (memq opcode '(continuation ping pong text binary)))) + (mask-key (when should-mask (websocket-genbytes 4)))) + (apply 'unibyte-string + (let ((val (append (list + (logior (cond ((eq opcode 'continuation) 0) + ((eq opcode 'text) 1) + ((eq opcode 'binary) 2) + ((eq opcode 'close) 8) + ((eq opcode 'ping) 9) + ((eq opcode 'pong) 10)) + (if fin 128 0))) + (when payloadp + (list + (logior + (if should-mask 128 0) + (cond ((< (length payload) 126) (length payload)) + ((< (length payload) 65536) 126) + (t 127))))) + (when (and payloadp (>= (length payload) 126)) + (append (websocket-to-bytes + (length payload) + (cond ((< (length payload) 126) 1) + ((< (length payload) 65536) 2) + (t 8))) nil)) + (when (and payloadp should-mask) + (append mask-key nil)) + (when payloadp + (append (if should-mask (websocket-mask mask-key payload) + payload) + nil))))) + ;; We have to make sure the non-payload data is a full 32-bit frame + (if (= 1 (length val)) + (append val '(0)) val))))) + +(defun websocket-read-frame (s) + "Read from string S a `websocket-frame' struct with the contents. +This only gets complete frames. Partial frames need to wait until +the frame finishes. If the frame is not completed, return NIL." + (catch 'websocket-incomplete-frame + (websocket-ensure-length s 1) + (let* ((opcode (websocket-get-opcode s)) + (fin (logand 128 (websocket-get-bytes s 1))) + (payloadp (memq opcode '(continuation text binary ping pong))) + (payload-len (when payloadp + (websocket-get-payload-len (substring s 1)))) + (maskp (and + payloadp + (= 128 (logand 128 (websocket-get-bytes (substring s 1) 1))))) + (payload-start (when payloadp (+ (if maskp 5 1) (cdr payload-len)))) + (payload-end (when payloadp (+ payload-start (car payload-len)))) + (unmasked-payload (when payloadp + (websocket-ensure-length s payload-end) + (substring s payload-start payload-end)))) + (make-websocket-frame + :opcode opcode + :payload + (if maskp + (let ((masking-key (substring s (+ 1 (cdr payload-len)) + (+ 5 (cdr payload-len))))) + (websocket-mask masking-key unmasked-payload)) + unmasked-payload) + :length (if payloadp payload-end 1) + :completep (> fin 0))))) + +(defun websocket-format-error (err) + "Format an error message like command level does. +ERR should be a cons of error symbol and error data." + + ;; Formatting code adapted from `edebug-report-error' + (concat (or (get (car err) 'error-message) + (format "peculiar error (%s)" (car err))) + (when (cdr err) + (format ": %s" + (mapconcat #'prin1-to-string + (cdr err) ", "))))) + +(defun websocket-default-error-handler (_websocket type err) + "The default error handler used to handle errors in callbacks." + (display-warning 'websocket + (format "in callback `%S': %s" + type + (websocket-format-error err)) + :error)) + +;; Error symbols in use by the library +(put 'websocket-unsupported-protocol 'error-conditions + '(error websocket-error websocket-unsupported-protocol)) +(put 'websocket-unsupported-protocol 'error-message "Unsupported websocket protocol") +(put 'websocket-wss-needs-emacs-24 'error-conditions + '(error websocket-error websocket-unsupported-protocol + websocket-wss-needs-emacs-24)) +(put 'websocket-wss-needs-emacs-24 'error-message + "wss protocol is not supported for Emacs before version 24.") +(put 'websocket-received-error-http-response 'error-conditions + '(error websocket-error websocket-received-error-http-response)) +(put 'websocket-received-error-http-response 'error-message + "Error response received from websocket server") +(put 'websocket-invalid-header 'error-conditions + '(error websocket-error websocket-invalid-header)) +(put 'websocket-invalid-header 'error-message + "Invalid HTTP header sent") +(put 'websocket-illegal-frame 'error-conditions + '(error websocket-error websocket-illegal-frame)) +(put 'websocket-illegal-frame 'error-message + "Cannot send illegal frame to websocket") +(put 'websocket-closed 'error-conditions + '(error websocket-error websocket-closed)) +(put 'websocket-closed 'error-message + "Cannot send message to a closed websocket") +(put 'websocket-unparseable-frame 'error-conditions + '(error websocket-error websocket-unparseable-frame)) +(put 'websocket-unparseable-frame 'error-message + "Received an unparseable frame") +(put 'websocket-frame-too-large 'error-conditions + '(error websocket-error websocket-frame-too-large)) +(put 'websocket-frame-too-large 'error-message + "The frame being sent is too large for this emacs to handle") + +(defun websocket-intersect (a b) + "Simple list intersection, should function like Common Lisp's `intersection'." + (let ((result)) + (dolist (elem a (nreverse result)) + (when (member elem b) + (push elem result))))) + +(defun websocket-get-debug-buffer-create (websocket) + "Get or create the buffer corresponding to WEBSOCKET." + (let ((buf (get-buffer-create (format "*websocket %s debug*" + (websocket-url websocket))))) + (when (= 0 (buffer-size buf)) + (buffer-disable-undo buf)) + buf)) + +(defun websocket-debug (websocket msg &rest args) + "In the WEBSOCKET's debug buffer, send MSG, with format ARGS." + (when websocket-debug + (let ((buf (websocket-get-debug-buffer-create websocket))) + (save-excursion + (with-current-buffer buf + (goto-char (point-max)) + (insert "[WS] ") + (insert (apply 'format (append (list msg) args))) + (insert "\n")))))) + +(defun websocket-verify-response-code (output) + "Verify that OUTPUT contains a valid HTTP response code. +The only acceptable one to websocket is responce code 101. +A t value will be returned on success, and an error thrown +if not." + (unless (string-match "^HTTP/1.1 \\([[:digit:]]+\\)" output) + (signal 'websocket-invalid-header "Invalid HTTP status line")) + (unless (equal "101" (match-string 1 output)) + (signal 'websocket-received-error-http-response + (string-to-number (match-string 1 output)))) + t) + +(defun websocket-parse-repeated-field (output field) + "From header-containing OUTPUT, parse out the list from a +possibly repeated field." + (let ((pos 0) + (extensions)) + (while (and pos + (string-match (format "\r\n%s: \\(.*\\)\r\n" field) + output pos)) + (when (setq pos (match-end 1)) + (setq extensions (append extensions (split-string + (match-string 1 output) ", ?"))))) + extensions)) + +(defun websocket-process-frame (websocket frame) + "Using the WEBSOCKET's filter and connection, process the FRAME. +This returns a lambda that should be executed when all frames have +been processed. If the frame has a payload, the lambda has the frame +passed to the filter slot of WEBSOCKET. If the frame is a ping, +the lambda has a reply with a pong. If the frame is a close, the lambda +has connection termination." + (let ((opcode (websocket-frame-opcode frame))) + (lexical-let ((lex-ws websocket) + (lex-frame frame)) + (cond ((memq opcode '(continuation text binary)) + (lambda () (websocket-try-callback 'websocket-on-message 'on-message + lex-ws lex-frame))) + ((eq opcode 'ping) + (lambda () (websocket-send lex-ws + (make-websocket-frame + :opcode 'pong + :payload (websocket-frame-payload lex-frame) + :completep t)))) + ((eq opcode 'close) + (lambda () (delete-process (websocket-conn lex-ws)))) + (t (lambda ())))))) + +(defun websocket-process-input-on-open-ws (websocket text) + "This handles input processing for both the client and server filters." + (let ((current-frame) + (processing-queue) + (start-point 0)) + (while (setq current-frame (websocket-read-frame + (substring text start-point))) + (push (websocket-process-frame websocket current-frame) processing-queue) + (incf start-point (websocket-frame-length current-frame))) + (when (> (length text) start-point) + (setf (websocket-inflight-input websocket) + (substring text start-point))) + (dolist (to-process (nreverse processing-queue)) + (funcall to-process)))) + +(defun websocket-send-text (websocket text) + "To the WEBSOCKET, send TEXT as a complete frame." + (websocket-send + websocket + (make-websocket-frame :opcode 'text + :payload (encode-coding-string + text 'raw-text) + :completep t))) + +(defun websocket-check (frame) + "Check FRAME for correctness, returning true if correct." + (or + ;; Text, binary, and continuation frames need payloads + (and (memq (websocket-frame-opcode frame) '(text binary continuation)) + (websocket-frame-payload frame)) + ;; Pings and pongs may optionally have them + (memq (websocket-frame-opcode frame) '(ping pong)) + ;; And close shouldn't have any payload, and should always be complete. + (and (eq (websocket-frame-opcode frame) 'close) + (not (websocket-frame-payload frame)) + (websocket-frame-completep frame)))) + +(defun websocket-send (websocket frame) + "To the WEBSOCKET server, send the FRAME. +This will raise an error if the frame is illegal. + +The error signaled may be of type `websocket-illegal-frame' if +the frame is malformed in some way, also having the condition +type of `websocket-error'. The data associated with the signal +is the frame being sent. + +If the websocket is closed a signal `websocket-closed' is sent, +also with `websocket-error' condition. The data in the signal is +also the frame. + +The frame may be too large for this buid of Emacs, in which case +`websocket-frame-too-large' is returned, with the data of the +size of the frame which was too large to process. This also has +the `websocket-error' condition." + (unless (websocket-check frame) + (signal 'websocket-illegal-frame frame)) + (websocket-debug websocket "Sending frame, opcode: %s payload: %s" + (websocket-frame-opcode frame) + (websocket-frame-payload frame)) + (websocket-ensure-connected websocket) + (unless (websocket-openp websocket) + (signal 'websocket-closed frame)) + (process-send-string (websocket-conn websocket) + ;; We mask only when we're a client, following the spec. + (websocket-encode-frame frame (not (websocket-server-p websocket))))) + +(defun websocket-openp (websocket) + "Check WEBSOCKET and return non-nil if it is open, and either +connecting or open." + (and websocket + (not (eq 'close (websocket-ready-state websocket))) + (member (process-status (websocket-conn websocket)) '(open run)))) + +(defun websocket-close (websocket) + "Close WEBSOCKET and erase all the old websocket data." + (websocket-debug websocket "Closing websocket") + (websocket-try-callback 'websocket-on-close 'on-close websocket) + (when (websocket-openp websocket) + (websocket-send websocket + (make-websocket-frame :opcode 'close + :completep t)) + (setf (websocket-ready-state websocket) 'closed)) + (delete-process (websocket-conn websocket))) + +(defun websocket-ensure-connected (websocket) + "If the WEBSOCKET connection is closed, open it." + (unless (and (websocket-conn websocket) + (ecase (process-status (websocket-conn websocket)) + ((run open listen) t) + ((stop exit signal closed connect failed nil) nil))) + (websocket-close websocket) + (websocket-open (websocket-url websocket) + :protocols (websocket-protocols websocket) + :extensions (websocket-extensions websocket) + :on-open (websocket-on-open websocket) + :on-message (websocket-on-message websocket) + :on-close (websocket-on-close websocket) + :on-error (websocket-on-error websocket)))) + +;;;;;;;;;;;;;;;;;;;;;; +;; Websocket client ;; +;;;;;;;;;;;;;;;;;;;;;; + +(defun* websocket-open (url &key protocols extensions (on-open 'identity) + (on-message (lambda (_w _f))) (on-close 'identity) + (on-error 'websocket-default-error-handler)) + "Open a websocket connection to URL, returning the `websocket' struct. +The PROTOCOL argument is optional, and setting it will declare to +the server that this client supports the protocols in the list +given. We will require that the server also has to support that +protocols. + +Similar logic applies to EXTENSIONS, which is a list of conses, +the car of which is a string naming the extension, and the cdr of +which is the list of parameter strings to use for that extension. +The parameter strings are of the form \"key=value\" or \"value\". +EXTENSIONS can be NIL if none are in use. An example value would +be (\"deflate-stream\" . (\"mux\" \"max-channels=4\")). + +Cookies that are set via `url-cookie-store' will be used during +communication with the server, and cookies received from the +server will be stored in the same cookie storage that the +`url-cookie' package uses. + +Optionally you can specify +ON-OPEN, ON-MESSAGE and ON-CLOSE callbacks as well. + +The ON-OPEN callback is called after the connection is +established with the websocket as the only argument. The return +value is unused. + +The ON-MESSAGE callback is called after receiving a frame, and is +called with the websocket as the first argument and +`websocket-frame' struct as the second. The return value is +unused. + +The ON-CLOSE callback is called after the connection is closed, or +failed to open. It is called with the websocket as the only +argument, and the return value is unused. + +The ON-ERROR callback is called when any of the other callbacks +have an error. It takes the websocket as the first argument, and +a symbol as the second argument either `on-open', `on-message', +or `on-close', and the error as the third argument. Do NOT +rethrow the error, or else you may miss some websocket messages. +You similarly must not generate any other errors in this method. +If you want to debug errors, set +`websocket-callback-debug-on-error' to t, but this also can be +dangerous is the debugger is quit out of. If not specified, +`websocket-default-error-handler' is used. + +For each of these event handlers, the client code can store +arbitrary data in the `client-data' slot in the returned +websocket. + +The following errors might be thrown in this method or in +websocket processing, all of them having the error-condition +`websocket-error' in addition to their own symbol: + +`websocket-unsupported-protocol': Data in the error signal is the +protocol that is unsupported. For example, giving a URL starting +with http by mistake raises this error. + +`websocket-wss-needs-emacs-24': Trying to connect wss protocol +using Emacs < 24 raises this error. You can catch this error +also by `websocket-unsupported-protocol'. + +`websocket-received-error-http-response': Data in the error +signal is the integer error number. + +`websocket-invalid-header': Data in the error is a string +describing the invalid header received from the server. + +`websocket-unparseable-frame': Data in the error is a string +describing the problem with the frame. +" + (let* ((name (format "websocket to %s" url)) + (url-struct (url-generic-parse-url url)) + (key (websocket-genkey)) + (coding-system-for-read 'binary) + (coding-system-for-write 'binary) + (conn (if (member (url-type url-struct) '("ws" "wss")) + (let* ((type (if (equal (url-type url-struct) "ws") + 'plain 'tls)) + (port (if (= 0 (url-port url-struct)) + (if (eq type 'tls) 443 80) + (url-port url-struct))) + (host (url-host url-struct))) + (if (eq type 'plain) + (make-network-process :name name :buffer nil :host host + :service port :nowait nil) + (condition-case-unless-debug nil + (open-network-stream name nil host port :type type :nowait nil) + (wrong-number-of-arguments + (signal 'websocket-wss-needs-emacs-24 "wss"))))) + (signal 'websocket-unsupported-protocol (url-type url-struct)))) + (websocket (websocket-inner-create + :conn conn + :url url + :on-open on-open + :on-message on-message + :on-close on-close + :on-error on-error + :protocols protocols + :extensions (mapcar 'car extensions) + :accept-string + (websocket-calculate-accept key)))) + (unless conn (error "Could not establish the websocket connection to %s" url)) + (process-put conn :websocket websocket) + (set-process-filter conn + (lambda (process output) + (let ((websocket (process-get process :websocket))) + (websocket-outer-filter websocket output)))) + (set-process-sentinel + conn + (lambda (process change) + (let ((websocket (process-get process :websocket))) + (websocket-debug websocket "State change to %s" change) + (when (and + (member (process-status process) '(closed failed exit signal)) + (not (eq 'closed (websocket-ready-state websocket)))) + (websocket-try-callback 'websocket-on-close 'on-close websocket))))) + (set-process-query-on-exit-flag conn nil) + (process-send-string conn + (format "GET %s HTTP/1.1\r\n" + (let ((path (url-filename url-struct))) + (if (> (length path) 0) path "/")))) + (websocket-debug websocket "Sending handshake, key: %s, acceptance: %s" + key (websocket-accept-string websocket)) + (process-send-string conn + (websocket-create-headers url key protocols extensions)) + (websocket-debug websocket "Websocket opened") + websocket)) + +(defun websocket-process-headers (url headers) + "On opening URL, process the HEADERS sent from the server." + (when (string-match "Set-Cookie: \(.*\)\r\n" headers) + ;; The url-current-object is assumed to be set by + ;; url-cookie-handle-set-cookie. + (let ((url-current-object (url-generic-parse-url url))) + (url-cookie-handle-set-cookie (match-string 1 headers))))) + +(defun websocket-outer-filter (websocket output) + "Filter the WEBSOCKET server's OUTPUT. +This will parse headers and process frames repeatedly until there +is no more output or the connection closes. If the websocket +connection is invalid, the connection will be closed." + (websocket-debug websocket "Received: %s" output) + (let ((start-point) + (text (concat (websocket-inflight-input websocket) output)) + (header-end-pos)) + (setf (websocket-inflight-input websocket) nil) + ;; If we've received the complete header, check to see if we've + ;; received the desired handshake. + (when (and (eq 'connecting (websocket-ready-state websocket))) + (if (and (setq header-end-pos (string-match "\r\n\r\n" text)) + (setq start-point (+ 4 header-end-pos))) + (progn + (condition-case err + (progn + (websocket-verify-response-code text) + (websocket-verify-headers websocket text) + (websocket-process-headers (websocket-url websocket) text)) + (error + (websocket-close websocket) + (signal (car err) (cdr err)))) + (setf (websocket-ready-state websocket) 'open) + (websocket-try-callback 'websocket-on-open 'on-open websocket)) + (setf (websocket-inflight-input websocket) text))) + (when (eq 'open (websocket-ready-state websocket)) + (websocket-process-input-on-open-ws + websocket (substring text (or start-point 0)))))) + +(defun websocket-verify-headers (websocket output) + "Based on WEBSOCKET's data, ensure the headers in OUTPUT are valid. +The output is assumed to have complete headers. This function +will either return t or call `error'. This has the side-effect +of populating the list of server extensions to WEBSOCKET." + (let ((accept-string + (concat "Sec-WebSocket-Accept: " (websocket-accept-string websocket)))) + (websocket-debug websocket "Checking for accept header: %s" accept-string) + (unless (string-match (regexp-quote accept-string) output) + (signal 'websocket-invalid-header + "Incorrect handshake from websocket: is this really a websocket connection?"))) + (let ((case-fold-search t)) + (websocket-debug websocket "Checking for upgrade header") + (unless (string-match "\r\nUpgrade: websocket\r\n" output) + (signal 'websocket-invalid-header + "No 'Upgrade: websocket' header found")) + (websocket-debug websocket "Checking for connection header") + (unless (string-match "\r\nConnection: upgrade\r\n" output) + (signal 'websocket-invalid-header + "No 'Connection: upgrade' header found")) + (when (websocket-protocols websocket) + (dolist (protocol (websocket-protocols websocket)) + (websocket-debug websocket "Checking for protocol match: %s" + protocol) + (let ((protocols + (if (string-match (format "\r\nSec-Websocket-Protocol: %s\r\n" + protocol) + output) + (list protocol) + (signal 'websocket-invalid-header + "Incorrect or missing protocol returned by the server.")))) + (setf (websocket-negotiated-protocols websocket) protocols)))) + (let* ((extensions (websocket-parse-repeated-field + output + "Sec-WebSocket-Extensions")) + (extra-extensions)) + (dolist (ext extensions) + (let ((x (first (split-string ext "; ?")))) + (unless (or (member x (websocket-extensions websocket)) + (member x extra-extensions)) + (push x extra-extensions)))) + (when extra-extensions + (signal 'websocket-invalid-header + (format "Non-requested extensions returned by server: %S" + extra-extensions))) + (setf (websocket-negotiated-extensions websocket) extensions))) + t) + +;;;;;;;;;;;;;;;;;;;;;; +;; Websocket server ;; +;;;;;;;;;;;;;;;;;;;;;; + +(defvar websocket-server-websockets nil + "A list of current websockets live on any server.") + +(defun* websocket-server (port &rest plist) + "Open a websocket server on PORT. +If the plist contains a `:host' HOST pair, this value will be +used to configure the addresses the socket listens on. The symbol +`local' specifies the local host. If unspecified or nil, the +socket will listen on all addresses. + +This also takes a plist of callbacks: `:on-open', `:on-message', +`:on-close' and `:on-error', which operate exactly as documented +in the websocket client function `websocket-open'. Returns the +connection, which should be kept in order to pass to +`websocket-server-close'." + (let* ((conn (make-network-process + :name (format "websocket server on port %s" port) + :server t + :family 'ipv4 + :noquery t + :filter 'websocket-server-filter + :log 'websocket-server-accept + :filter-multibyte nil + :plist plist + :host (plist-get plist :host) + :service port))) + conn)) + +(defun websocket-server-close (conn) + "Closes the websocket, as well as all open websockets for this server." + (let ((to-delete)) + (dolist (ws websocket-server-websockets) + (when (eq (websocket-server-conn ws) conn) + (if (eq (websocket-ready-state ws) 'closed) + (unless (member ws to-delete) + (push ws to-delete)) + (websocket-close ws)))) + (dolist (ws to-delete) + (setq websocket-server-websockets (remove ws websocket-server-websockets)))) + (delete-process conn)) + +(defun websocket-server-accept (server client _message) + "Accept a new websocket connection from a client." + (let ((ws (websocket-inner-create + :server-conn server + :conn client + :url client + :server-p t + :on-open (or (process-get server :on-open) 'identity) + :on-message (or (process-get server :on-message) (lambda (_ws _frame))) + :on-close (lexical-let ((user-method + (or (process-get server :on-close) 'identity))) + (lambda (ws) + (setq websocket-server-websockets + (remove ws websocket-server-websockets)) + (funcall user-method ws))) + :on-error (or (process-get server :on-error) + 'websocket-default-error-handler) + :protocols (process-get server :protocol) + :extensions (mapcar 'car (process-get server :extensions))))) + (unless (member ws websocket-server-websockets) + (push ws websocket-server-websockets)) + (process-put client :websocket ws) + (set-process-coding-system client 'binary 'binary) + (set-process-sentinel client + (lambda (process change) + (let ((websocket (process-get process :websocket))) + (websocket-debug websocket "State change to %s" change) + (when (and + (member (process-status process) '(closed failed exit signal)) + (not (eq 'closed (websocket-ready-state websocket)))) + (websocket-try-callback 'websocket-on-close 'on-close websocket))))))) + +(defun websocket-create-headers (url key protocol extensions) + "Create connections headers for the given URL, KEY, PROTOCOL and EXTENSIONS. +These are defined as in `websocket-open'." + (let* ((parsed-url (url-generic-parse-url url)) + (host-port (if (url-port-if-non-default parsed-url) + (format "%s:%s" (url-host parsed-url) (url-port parsed-url)) + (url-host parsed-url))) + (cookie-header (url-cookie-generate-header-lines + host-port (car (url-path-and-query parsed-url)) + (equal (url-type parsed-url) "wss")))) + (format (concat "Host: %s\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Key: %s\r\n" + "Sec-WebSocket-Version: 13\r\n" + (when protocol + (concat + (mapconcat + (lambda (protocol) + (format "Sec-WebSocket-Protocol: %s" protocol)) + protocol "\r\n") + "\r\n")) + (when extensions + (format "Sec-WebSocket-Extensions: %s\r\n" + (mapconcat + (lambda (ext) + (concat + (car ext) + (when (cdr ext) "; ") + (when (cdr ext) + (mapconcat 'identity (cdr ext) "; ")))) + extensions ", "))) + (when cookie-header cookie-header) + "\r\n") + host-port + key + protocol))) + +(defun websocket-get-server-response (websocket client-protocols client-extensions) + "Get the websocket response from client WEBSOCKET." + (let ((separator "\r\n")) + (concat "HTTP/1.1 101 Switching Protocols" separator + "Upgrade: websocket" separator + "Connection: Upgrade" separator + "Sec-WebSocket-Accept: " + (websocket-accept-string websocket) separator + (let ((protocols + (websocket-intersect client-protocols + (websocket-protocols websocket)))) + (when protocols + (concat + (mapconcat + (lambda (protocol) (format "Sec-WebSocket-Protocol: %s" + protocol)) protocols separator) + separator))) + (let ((extensions (websocket-intersect + client-extensions + (websocket-extensions websocket)))) + (when extensions + (concat + (mapconcat + (lambda (extension) (format "Sec-Websocket-Extensions: %s" + extension)) extensions separator) + separator))) + separator))) + +(defun websocket-server-filter (process output) + "This acts on all OUTPUT from websocket clients PROCESS." + (let* ((ws (process-get process :websocket)) + (text (concat (websocket-inflight-input ws) output))) + (setf (websocket-inflight-input ws) nil) + (cond ((eq (websocket-ready-state ws) 'connecting) + ;; check for connection string + (let ((end-of-header-pos + (let ((pos (string-match "\r\n\r\n" text))) + (when pos (+ 4 pos))))) + (if end-of-header-pos + (progn + (let ((header-info (websocket-verify-client-headers text))) + (if header-info + (progn (setf (websocket-accept-string ws) + (websocket-calculate-accept + (plist-get header-info :key))) + (process-send-string + process + (websocket-get-server-response + ws (plist-get header-info :protocols) + (plist-get header-info :extensions))) + (setf (websocket-ready-state ws) 'open) + (websocket-try-callback 'websocket-on-open + 'on-open ws)) + (message "Invalid client headers found in: %s" output) + (process-send-string process "HTTP/1.1 400 Bad Request\r\n\r\n") + (websocket-close ws))) + (when (> (length text) (+ 1 end-of-header-pos)) + (websocket-server-filter process (substring + text + end-of-header-pos)))) + (setf (websocket-inflight-input ws) text)))) + ((eq (websocket-ready-state ws) 'open) + (websocket-process-input-on-open-ws ws text)) + ((eq (websocket-ready-state ws) 'closed) + (message "WARNING: Should not have received further input on closed websocket"))))) + +(defun websocket-verify-client-headers (output) + "Verify the headers from the WEBSOCKET client connection in OUTPUT. +Unlike `websocket-verify-headers', this is a quieter routine. We +don't want to error due to a bad client, so we just print out +messages and a plist containing `:key', the websocket key, +`:protocols' and `:extensions'." + (block nil + (let ((case-fold-search t) + (plist)) + (unless (string-match "HTTP/1.1" output) + (message "Websocket client connection: HTTP/1.1 not found") + (return nil)) + (unless (string-match "^Host: " output) + (message "Websocket client connection: Host header not found") + (return nil)) + (unless (string-match "^Upgrade: websocket\r\n" output) + (message "Websocket client connection: Upgrade: websocket not found") + (return nil)) + (if (string-match "^Sec-WebSocket-Key: \\([[:graph:]]+\\)\r\n" output) + (setq plist (plist-put plist :key (match-string 1 output))) + (message "Websocket client connect: No key sent") + (return nil)) + (unless (string-match "^Sec-WebSocket-Version: 13" output) + (message "Websocket client connect: Websocket version 13 not found") + (return nil)) + (when (string-match "^Sec-WebSocket-Protocol:" output) + (setq plist (plist-put plist :protocols (websocket-parse-repeated-field + output + "Sec-Websocket-Protocol")))) + (when (string-match "^Sec-WebSocket-Extensions:" output) + (setq plist (plist-put plist :extensions (websocket-parse-repeated-field + output + "Sec-Websocket-Extensions")))) + plist))) + +(provide 'websocket) + +;;; websocket.el ends here diff --git a/emacs-custom.el b/emacs-custom.el index b4b4465..b1147e1 100644 --- a/emacs-custom.el +++ b/emacs-custom.el @@ -34,14 +34,10 @@ '(diff-mode-hook (quote ((lambda nil (diff-auto-refine-mode 1))))) '(diff-switches "-u") '(dtrt-indent-mode t nil (dtrt-indent)) + '(ediff-window-setup-function (quote ediff-setup-windows-plain)) '(edit-server-done-hook nil) '(edit-server-new-frame nil) '(fill-column 98) - '(flymake-allowed-file-name-masks - (quote - (("\\.java\\'" flymake-simple-make-java-init flymake-simple-java-cleanup) - ("[0-9]+\\.tex\\'" flymake-master-tex-init flymake-master-cleanup) - ("\\.tex\\'" flymake-simple-tex-init)))) '(flyspell-delay 30) '(flyspell-delayed-commands nil) '(frame-background-mode (quote light)) @@ -60,9 +56,9 @@ '(hs-isearch-open nil) '(ido-mode (quote both) nil (ido)) '(indent-tabs-mode nil) - '(ispell-dictionary "deutsch8") + '(ispell-dictionary "american") '(ispell-extra-args (quote ("--sug-mode=ultra"))) - '(ispell-program-name "c:/cygwin/bin/aspell.exe") + '(ispell-program-name "aspell") '(line-move-visual nil) '(ls-lisp-dirs-first t) '(magit-default-tracking-name-function (quote magit-default-tracking-name-branch-only)) @@ -82,7 +78,8 @@ '(rtags-use-helm nil t) '(safe-local-variable-values (quote - ((elisp-project-autoload-file-name . "sqi-autoload.el") + ((ispell-local-dictionary . de_DE-neu) + (elisp-project-autoload-file-name . "sqi-autoload.el") (elisp-project-autoload-file-name . "cc-autoload.el") (ccide-auto-format-tag . "auto-uncrustify") (ccide-uncrustify-config . "~/src/search.uncrustify") diff --git a/gnuplot/autoload.el b/gnuplot/load.el similarity index 100% rename from gnuplot/autoload.el rename to gnuplot/load.el diff --git a/python/init_python.el b/python/init_python.el index 9067c16..4c71a2d 100644 --- a/python/init_python.el +++ b/python/init_python.el @@ -4,6 +4,9 @@ ;(require 'python-mode) ;(provide 'python) ;(provide 'python21) + +(global-unset-key "\C-xpn") + (require 'python) ;; pymacs @@ -25,8 +28,6 @@ (define-key ropemacs-local-keymap "\M-/" 'hippie-expand) -(global-unset-key "\C-xpn") - (defun write-file-py-cleanup-imports () (save-excursion (condition-case nil @@ -230,67 +231,69 @@ ;;; 2) Yasnippet ;;; all with AutoComplete.el ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defun prefix-list-elements (list prefix) - (let (value) - (nreverse - (dolist (element list value) - (setq value (cons (format "%s%s" prefix element) value)))))) -(defvar ac-source-rope - '((candidates - . (lambda () - (prefix-list-elements (rope-completions) ac-target)))) - "Source for Rope") -(defun ac-python-find () - "Python `ac-find-function'." - (require 'thingatpt) - (let ((symbol (car-safe (bounds-of-thing-at-point 'symbol)))) - (if (null symbol) +(if nil + (defun prefix-list-elements (list prefix) + (let (value) + (nreverse + (dolist (element list value) + (setq value (cons (format "%s%s" prefix element) value)))))) + (defvar ac-source-rope + '((candidates + . (lambda () + (prefix-list-elements (rope-completions) ac-target)))) + "Source for Rope") + (defun ac-python-find () + "Python `ac-find-function'." + (require 'thingatpt) + (let ((symbol (car-safe (bounds-of-thing-at-point 'symbol)))) + (if (null symbol) (if (string= "." (buffer-substring (- (point) 1) (point))) - (point) + (point) nil) - symbol))) -(defun ac-python-candidate () - "Python `ac-candidates-function'" - (let (candidates) - (dolist (source ac-sources) - (if (symbolp source) + symbol))) + (defun ac-python-candidate () + "Python `ac-candidates-function'" + (let (candidates) + (dolist (source ac-sources) + (if (symbolp source) (setq source (symbol-value source))) - (let* ((ac-limit (or (cdr-safe (assq 'limit source)) ac-limit)) - (requires (cdr-safe (assq 'requires source))) - cand) - (if (or (null requires) - (>= (length ac-target) requires)) + (let* ((ac-limit (or (cdr-safe (assq 'limit source)) ac-limit)) + (requires (cdr-safe (assq 'requires source))) + cand) + (if (or (null requires) + (>= (length ac-target) requires)) (setq cand (delq nil (mapcar (lambda (candidate) (propertize candidate 'source source)) (funcall (cdr (assq 'candidates source))))))) - (if (and (> ac-limit 1) - (> (length cand) ac-limit)) + (if (and (> ac-limit 1) + (> (length cand) ac-limit)) (setcdr (nthcdr (1- ac-limit) cand) nil)) - (setq candidates (append candidates cand)))) - (delete-dups candidates))) -(add-hook 'python-mode-hook - (lambda () - (auto-complete-mode 1) - (set (make-local-variable 'ac-sources) - (append ac-sources '(ac-source-rope) '(ac-source-yasnippet))) - (set (make-local-variable 'ac-find-function) 'ac-python-find) - (set (make-local-variable 'ac-candidate-function) 'ac-python-candidate) - (set (make-local-variable 'ac-auto-start) nil))) -;;Ryan's python specific tab completion -(defun ryan-python-tab () - ; Try the following: - ; 1) Do a yasnippet expansion - ; 2) Do a Rope code completion - ; 3) Do an indent - (interactive) - (if (eql (ac-start) 0) + (setq candidates (append candidates cand)))) + (delete-dups candidates))) + (add-hook 'python-mode-hook + (lambda () + (auto-complete-mode 1) + (set (make-local-variable 'ac-sources) + (append ac-sources '(ac-source-rope) '(ac-source-yasnippet))) + (set (make-local-variable 'ac-find-function) 'ac-python-find) + (set (make-local-variable 'ac-candidate-function) 'ac-python-candidate) + (set (make-local-variable 'ac-auto-start) nil))) + ;;Ryan's python specific tab completion + (defun ryan-python-tab () + ; Try the following: + ; 1) Do a yasnippet expansion + ; 2) Do a Rope code completion + ; 3) Do an indent + (interactive) + (if (eql (ac-start) 0) (indent-for-tab-command))) -(defadvice ac-start (before advice-turn-on-auto-start activate) - (set (make-local-variable 'ac-auto-start) t)) -(defadvice ac-cleanup (after advice-turn-off-auto-start activate) - (set (make-local-variable 'ac-auto-start) nil)) + (defadvice ac-start (before advice-turn-on-auto-start activate) + (set (make-local-variable 'ac-auto-start) t)) + (defadvice ac-cleanup (after advice-turn-off-auto-start activate) + (set (make-local-variable 'ac-auto-start) nil)) + ) ;(define-key py-mode-map "\t" 'ryan-python-tab) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; End Auto Completion diff --git a/setup/bindings.el b/setup/bindings.el index 8e4e79c..8112606 100644 --- a/setup/bindings.el +++ b/setup/bindings.el @@ -1,5 +1,5 @@ (global-set-key "\M-/" 'hippie-expand) -(global-set-key "\C-c'w" 'which-func-mode) +(global-set-key "\C-c'w" 'which-function-mode) (global-set-key "\C-c'h" 'highlight-changes-mode) (global-set-key "\C-c'f" 'auto-fill-mode) (global-set-key "\C-c'v" 'visual-line-mode) @@ -8,6 +8,7 @@ (global-set-key "\C-c'g" 'toggle-debug-on-quit) (global-set-key "\C-c'c" 'toggle-case-fold-search) (global-set-key "\C-c's" 'flyspell-mode) +(global-set-key "\C-c'S" 'flyspell-prog-mode) (global-set-key "\C-c'a" 'global-auto-revert-mode) (global-set-key "\C-cF" 'ffap) @@ -20,16 +21,23 @@ ;; * everything as globaly configured ;; * as above but disable lines-tail ;; * nothing + ;; * as above but visualize tabs + + ;; if mode is not set, detect current mode and set it to the next value in the list (if (null mode) (if (local-variable-p 'whitespace-style) (if (null whitespace-style) - (setq mode 'default) - (setq mode 'none)) + (setq mode 'tabs) + (if (memq 'tab-mark whitespace-style) + (setq mode 'default) + (setq mode 'none))) (setq mode 'longlines))) (cond ((eq mode 'default) (kill-local-variable 'whitespace-style)) ((eq mode 'longlines) (setq-local whitespace-style (remove 'lines-tail (default-value 'whitespace-style)))) + ((eq mode 'tabs) + (setq-local whitespace-style '(tab-mark))) ((eq mode 'none) (setq-local whitespace-style nil))) (whitespace-mode -1) @@ -40,3 +48,21 @@ (global-set-key "\C-c' " 'toggle-whitespace-mode) (setq confirm-kill-emacs 'yes-or-no-p) + +(defun kill-buffers-in-directory (directoryName &optional includeNonFiles) + (interactive (list + (ido-read-directory-name + (if current-prefix-arg "Kill buffers in directory:" "Kill files in directory: ")) + current-prefix-arg)) + (setq directoryName (expand-file-name directoryName)) + (if (not (string-suffix-p "/" directoryName)) + (setq directoryName (concat directoryName "/"))) + (loop for buffer in (buffer-list) + for bufferDirectory = (progn + (set-buffer buffer) + (if includeNonFiles default-directory + (and buffer-file-name (file-name-directory buffer-file-name)))) + if (and bufferDirectory (string-prefix-p directoryName (expand-file-name bufferDirectory))) + do (kill-buffer buffer))) + +(global-set-key "\C-xK" 'kill-buffers-in-directory) diff --git a/setup/eshell.el b/setup/eshell.el index 1f836ac..3a72ff0 100644 --- a/setup/eshell.el +++ b/setup/eshell.el @@ -16,10 +16,15 @@ (eshell-buffer (get-buffer "*eshell*"))) (if (not eshell-buffer) (error "no *eshell* buffer found")) - (pop-to-buffer (get-buffer "*eshell*")) + (my-pop-to-buffer (get-buffer "*eshell*")) (goto-char (point-max)) (setq default-directory dir) - (insert "\n") - (eshell-send-input))) + (eshell-interrupt-process))) (global-set-key "\C-cE" 'eshell-switch-directory-current-buffer) + +(setenv "PATH" (concat (getenv "PATH") + ":" + (expand-file-name "~/bin") + ":" + (expand-file-name "~/.local/bin"))) diff --git a/setup/flyspell.el b/setup/flyspell.el index 1352979..6f580fd 100644 --- a/setup/flyspell.el +++ b/setup/flyspell.el @@ -2,5 +2,5 @@ ; Speed up interactivity in flyspell (it's unusable on windows otherwise) -(defadvice flyspell-check-pre-word-p (around flyspell-delay-all activate) - (setq ad-return-value nil)) +; (defadvice flyspell-check-pre-word-p (around flyspell-delay-all activate) +; (setq ad-return-value nil)) diff --git a/setup/gnuplot.el b/setup/gnuplot.el index b0ed624..d54f242 100644 --- a/setup/gnuplot.el +++ b/setup/gnuplot.el @@ -5,10 +5,10 @@ buffer-file-name)))) (file-name-as-directory "gnuplot")))) (add-to-list 'load-path dir) - (load (concat dir "autoload.el"))) + (load (concat dir "load.el"))) (defun gnuplot () (interactive) (gnuplot-make-gnuplot-buffer) (sit-for .1) - (switch-to-buffer "*gnuplot*")) \ No newline at end of file + (switch-to-buffer "*gnuplot*")) diff --git a/setup/magit.el b/setup/magit.el index 8ae6b76..91c70f2 100644 --- a/setup/magit.el +++ b/setup/magit.el @@ -36,8 +36,70 @@ (require 'magit) -(setq magit-refs-local-branch-format "%C %-48n %U%m\n") -(setq magit-refs-remote-branch-format "%C %-48n %m\n") +;; Add additional %-escapes ... +(defun magit-insert-branch-1 + (section branch format current branches face + &optional hash message upstream ahead behind gone) + "For internal use, don't add to a hook." + (let* ((head (or (car magit-refresh-args) current "HEAD")) + (count (and branch + (magit-refs-format-commit-count branch head format))) + (mark (cond ((or (equal branch head) + (and (not branch) (equal head "HEAD"))) + (if (equal branch current) + (propertize "@" 'face 'magit-head) + (propertize "#" 'face 'magit-tag))) + ((equal branch current) + (propertize "." 'face 'magit-head))))) + (when upstream + (setq upstream (propertize upstream 'face + (if (member upstream branches) + 'magit-branch-local + 'magit-branch-remote)))) + (magit-insert-heading + (format-spec + format + `((?a . ,(or ahead "")) + (?b . ,(or behind "")) + (?c . ,(or mark count "")) + (?C . ,(or mark " ")) + (?h . ,(or (propertize hash 'face 'magit-hash) "")) + (?m . ,(or message "")) + (?n . ,(propertize (or branch "(detached)") 'face face)) + (?u . ,(or upstream "")) + (?U . ,(if upstream (format (propertize " [%s]" 'face 'magit-dimmed) upstream) "")) + (?d . ,(if upstream + (let ((msg (cond + (gone + (concat (propertize gone 'face 'error))) + ((or ahead behind) + (concat (and ahead (format "ahead %s" ahead)) + (and ahead behind ", ") + (and behind (format "behind %s" behind)))) + (t nil)))) + (if msg + (format (propertize "[%s] " 'face 'magit-dimmed) msg) + "")) + "")) + (?D . ,(if upstream + (format (propertize "[%s%s] " 'face 'magit-dimmed) + upstream + (cond + (gone + (concat ": " (propertize gone 'face 'error))) + ((or ahead behind) + (concat ": " + (and ahead (format "ahead %s" ahead)) + (and ahead behind ", ") + (and behind (format "behind %s" behind)))) + (t ""))) + ""))))) + (when magit-show-margin + (magit-refs-format-margin branch)) + (magit-refs-insert-cherry-commits head branch section))) + +(setq magit-refs-local-branch-format "%C %-48n %-1.1u %d%m") +(setq magit-refs-remote-branch-format "%C %-48n %m") (when (eq system-type 'windows-nt) @@ -70,6 +132,7 @@ ad-do-it)) (global-set-key "\C-cGS" 'magit-status) +(global-set-key "\C-cGW" 'magit-file-popup) (defun my-shell-command-to-string (cmd) (shell-command cmd " *my-shell-command-to-string*") @@ -181,6 +244,13 @@ (magit-define-popup-switch 'magit-log-popup ?f "first parent" "--first-parent") +(defun magit-reset-to-upstream () + (interactive) + (magit-run-git "reset" "--hard" "@{u}")) + +(magit-define-popup-action 'magit-pull-popup + ?X "HARD Reset to upstream (force pull after remote rebase)" 'magit-reset-to-upstream) + (require 'ffap) (defun g0dil-magit-old-version-jump-to-current () diff --git a/setup/mywin.el b/setup/mywin.el index 4fde816..11891c8 100644 --- a/setup/mywin.el +++ b/setup/mywin.el @@ -22,7 +22,7 @@ to 80." window smaller than MIN-HEIGHT lines." (interactive) ;; this algorithm is copied from window.el / balance-windows() - (let ((min-height (or min-height i(+ window-min-height 0))) + (let ((min-height (or min-height (+ window-min-height 0))) (count -1) size) ;; Don't count the lines that are above the uppermost windows. @@ -61,6 +61,15 @@ window smaller than MIN-HEIGHT lines." (defvar my-windows-count nil) +(defun get-top-windows () + (let (topwindows) + (walk-windows (function (lambda (w) + (let ((e (window-edges w))) + (if (< (nth 1 e) window-min-height) + (setq topwindows (cons (cons (nth 0 e) w) topwindows))))))) + (loop for w in (sort topwindows (function (lambda (a b) (< (car a) (car b))))) + collect (cdr w) ))) + (defun setup-my-windows (&optional n) (interactive "P") (if n @@ -73,27 +82,22 @@ window smaller than MIN-HEIGHT lines." (min width) (distribute t) (currentbuffer (current-buffer)) (currentwindow (selected-window)) - topwindows firstwindow newwindow newtopwindows) - (walk-windows (function (lambda (w) - (let ((e (window-edges w))) - (if (< (nth 1 e) window-min-height) - (setq topwindows (cons (list (nth 0 e) - w - (window-buffer w) - (window-point w) - (window-start w) - (equal w currentwindow)) - topwindows)))))) - 'nomini) - (setq topwindows (sort topwindows (function (lambda (a b) (< (car a) (car b)))))) - (setq topwindows (loop for w in topwindows - for (pos win buf point start iscurrent) = w - if (not (member (buffer-name buf) setup-my-windows-junk-buffers)) - collect w)) + (topwindows (loop for w in (get-top-windows) + for b = (window-buffer w) + if (not (member (buffer-name b) + setup-my-windows-junk-buffers)) + collect (list (nth 0 (window-edges w)) + w + b + (window-point w) + (window-start w) + (equal w currentwindow)))) + firstwindow newwindow newtopwindows newbottomwindow) (delete-other-windows (nth 1 (car topwindows))) (save-selected-window - (select-window (split-window-vertically - (- (window-height) (max 5 (/ (* (frame-height) 15) 100)) -1))) + (setq newbottomwindow (split-window-vertically + (- (window-height) (max 5 (/ (* (frame-height) 15) 100)) -1))) + (select-window newbottomwindow) (switch-to-buffer (get-buffer-create "*compilation*")) (if (eq currentbuffer (current-buffer)) (setq newwindow (selected-window)))) @@ -148,19 +152,39 @@ window smaller than MIN-HEIGHT lines." (pjb-balance-windows t)) (select-window newwindow) (if (not (member (buffer-name currentbuffer) setup-my-windows-junk-buffers)) - (switch-to-buffer currentbuffer)))) + (switch-to-buffer currentbuffer)) + newbottomwindow)) (defun my-split-window-sensibly (window) (if (and (> (window-height window) (- (frame-height (window-frame window)) window-min-height)) (> (window-height window) (max 5 (/ (* (frame-height) 15) 100)))) (split-window-sensibly window))) +(defun my-pop-to-buffer (buffer) + ;; display buffer in rightmost window if not displayed currently + (let ((w (get-buffer-window buffer))) + (unless w + (setq w (car (last (get-top-windows))))) + (select-window w) + (switch-to-buffer buffer))) + +(defun my-display-at-bottom (&optional buffer) + ;; call my-setup-window and display current-buffer or BUFFER in bottom frame + (interactive) + (if (not buffer) (setq buffer (current-buffer))) + (bury-buffer) + ;; why does save-selected-window not work here ??? + (save-selected-window + (select-window (setup-my-windows)) + (switch-to-buffer buffer))) + (setq split-window-preferred-function 'my-split-window-sensibly) (global-set-key "\C-x7" 'split-window-3-horizontally) (global-set-key "\C-x8" (lambda () (interactive) (split-window-n-horizontally 100 50))) (global-set-key "\C-x9" 'setup-my-windows) (global-set-key "\C-\M-_" (lambda () (interactive) (safe-shrink-window 5))) +(global-set-key "\C-x_" 'my-display-at-bottom) (defun my-swap-window-to-right (&optional below) "If swap buffer in this window with buffer on the right. If BELOW is set, @@ -217,8 +241,10 @@ the buffer stack in the current window." (defun safe-max-window () (interactive) - (safe-max-window-horizontally) - (maximize-window 5)) + (maximize-window 5) + (condition-case nil + (safe-max-window-horizontally) + (error nil))) (global-set-key "\C-x=" 'safe-max-window) (global-set-key "\C-x-" 'maximize-window-15) diff --git a/setup/nxml.el b/setup/nxml.el index 9423ef2..2b8b733 100644 --- a/setup/nxml.el +++ b/setup/nxml.el @@ -74,11 +74,13 @@ (add-to-list 'hs-special-modes-alist '(nxml-mode ("\\(<[^/>]*>\\)$" 1) "]*>$")) -(defun nxml-enable-hs () +(defun nxml-setup () (setq nxml-sexp-element-flag t) - (hs-minor-mode 1)) + (hs-minor-mode 1) + (setq tab-width 2) + (toggle-whitespace-mode 'tabs)) -(add-hook 'nxml-mode-hook 'nxml-enable-hs) +(add-hook 'nxml-mode-hook 'nxml-setup) (defun hs-nxml-enter () (interactive) diff --git a/setup/rtags.el b/setup/rtags.el index 0d47656..b78dd64 100644 --- a/setup/rtags.el +++ b/setup/rtags.el @@ -33,6 +33,8 @@ (function rtags-find-symbol-at-point)) (define-key c-mode-base-map (kbd "\C-c,") (function rtags-find-references-at-point)) + (define-key c-mode-base-map (kbd "\C-cn") + (function rtags-next-diag)) ;; disable prelude's use of C-c r, as this is the rtags keyboard prefix ;; (define-key prelude-mode-map (kbd "C-c r") nil) ;; install standard rtags keybindings. Do M-. on the symbol below to diff --git a/setup/solarized-emacs.el b/setup/solarized-emacs.el index c57a3b3..411d8bc 100644 --- a/setup/solarized-emacs.el +++ b/setup/solarized-emacs.el @@ -10,3 +10,4 @@ ;(setq solarized-use-less-bold nil) (require 'solarized-light-theme) ;(set-face-attribute 'show-paren-match nil :weight 'extra-bold) +(set-face-attribute 'show-paren-match nil :foreground nil) diff --git a/setup/sticky.el b/setup/sticky.el new file mode 100644 index 0000000..edae8f1 --- /dev/null +++ b/setup/sticky.el @@ -0,0 +1,6 @@ +(define-minor-mode sticky-buffer-mode + "Make the current window always display this buffer." + nil " sticky" nil + (set-window-dedicated-p (selected-window) sticky-buffer-mode)) + +(global-set-key "\C-xS" 'sticky-buffer-mode) diff --git a/setup/x2go-hack.el b/setup/x2go-hack.el index 56ca33a..64af9db 100644 --- a/setup/x2go-hack.el +++ b/setup/x2go-hack.el @@ -1,8 +1,16 @@ (defvar ssh-agent-auth-sock-link "~/.ssh/ssh_auth_sock") +(defun g0dil-set-ssh-agent() + (message "SSH_AUTH_SOCK set to %s" ssh-agent-auth-sock-link) + (setenv "SSH_AUTH_SOCK" (expand-file-name ssh-agent-auth-sock-link))) + (defun g0dil-x2go-fix-ssh-agent () (let ((agent (getenv "SSH_AUTH_SOCK"))) - (if (string-match "^.*/\.x2go/.*/ssh-agent.PID" agent) - (setenv "SSH_AUTH_SOCK" (expand-file-name ssh-agent-auth-sock-link))))) + (if (and agent (string-match "^.*/\.x2go/.*/ssh-agent.PID" agent)) + (g0dil-set-ssh-agent)))) + +(defun g0dil-fix-ssh-agent () + (if (file-exists-p ssh-agent-auth-sock-link) + (g0dil-set-ssh-agent))) -(g0dil-x2go-fix-ssh-agent) +(g0dil-fix-ssh-agent) diff --git a/setup/zzz_finish.el b/setup/zzz_finish.el index 7cdb7ca..9f65e4b 100644 --- a/setup/zzz_finish.el +++ b/setup/zzz_finish.el @@ -17,3 +17,10 @@ (defadvice display-buffer-use-some-window (around no-resize activate) (flet ((window-resize (&rest args) nil)) ad-do-it)) + +; After everybody has had a chance to mess with flymake, remove the flymake modes which just don't work +(setq flymake-allowed-file-name-masks + (loop for elt in flymake-allowed-file-name-masks + if (not (member (car elt) '("\\.xml\\'" "\\.html?\\'" "\\.cs\\'" "\\.p[ml]\\'" + "\\.h\\'" "\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'"))) + collect elt))