diff --git a/.gitignore b/.gitignore index 78dae6e..2ed9952 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,22 @@ *~ *.elc *.pyc +ac-comphist.dat +.emacs.desktop* +tramp +eproject.lst +eproject.cfg +abbrev_defs +ede-projects.el +custom.el +site-lisp/ +/bookmarks.bmk +\177 *#*# -commit.txt \ No newline at end of file +commit.txt +.places +url/ +recentf +server/ +bookmarks +/elpa/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4590237 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "site-lisp/jump-char"] + path = site-lisp/jump-char + url = https://github.com/lewang/jump-char.git diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5da9fc6 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +.PHONY: clean all + +all: + echo "Do noting, stub. Better make clean." + +clean: + rm -f init.elc diff --git a/custom-nw.el b/custom-nw.el new file mode 100644 index 0000000..60bc2fc --- /dev/null +++ b/custom-nw.el @@ -0,0 +1,57 @@ +;; +(custom-set-variables + ;; custom-set-variables was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(TeX-PDF-mode t) + '(TeX-master nil) + '(TeX-source-correlate-method (quote synctex)) + '(TeX-source-correlate-mode t) + '(TeX-source-correlate-start-server (quote ask)) + '(ansi-color-names-vector + ["#2d3743" "#ff4242" "#74af68" "#dbdb95" "#34cae2" "#008b8b" "#00ede1" "#e1e1e0"]) + '(column-number-mode t) + '(custom-enabled-themes (quote (eugeneai-theme))) + '(custom-safe-themes + (quote + ("5ea08b040c5515152d2bcae79a05ae5c98339b5729c359d02437bf4cc567cca5" "e200f481e31ceee929079ad8a6f629e45bdad45e5ac27101c89d55f4827071db" "e885ba299f1f0f0927bc8b10136a704c1ec05c7d04b7011559439dd9e56c56ab" "6252dbc43eefee0edc82ef000659ece4f77c4c989b4571d8d23485efc5e9ef4d" "d5af8f6ee92912a7bac8185ed447e1e825252728a1ebd1d41eb2da660d27ad62" default))) + '(epy-load-yasnippet-p t) + '(ispell-dictionary "ru-yeyo") + '(load-prefer-newer t) + '(minibuffer-auto-raise t) + '(minibuffer-frame-alist (quote ((width . 80) (height . 1)))) + '(rw-hunspell-default-dictionary "russian") + '(rw-hunspell-dicpath-list (quote ("/usr/share/hunspell"))) + '(rw-hunspell-make-dictionary-menu t) + '(rw-hunspell-use-rw-ispell t) + '(safe-local-variable-values + (quote + ((TeX-auto-save . t) + (TeX-parse-self . t) + (major-mode . rst-mode) + (TeX-source-correlate-start-server) + (TeX-source-correlate-mode . 1) + (TeX-PDF-mode . 1) + (eval ispell-change-dictionary "ru_RU_hunspell") + (TeX-master . t) + (ispell-dictionary . american) + (py-indent-offset . 4) + (TeX-master . "dis") + (py-master-file . "/path/to/interactivetest.py") + (whitespace-line-column . 80) + (lexical-binding . t)))) + '(show-paren-mode t) + '(text-mode-hook (quote (turn-on-flyspell text-mode-hook-identify))) + '(tool-bar-mode nil) + '(w3-honor-stylesheets t) + '(which-function-mode nil)) +(custom-set-faces + ;; custom-set-faces was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(default ((t (:family "Fira Mono" :foundry "unknown" :slant normal :weight normal :height 159 :width normal)))) + '(minibuffer-prompt ((t (:foreground "CadetBlue1")))) + '(mode-line ((t (:background "gray75" :foreground "black" :weight normal :height 0.5 :family "Droid Sans")))) + '(mode-line-highlight ((t (:background "gold"))))) diff --git a/custom-w32.el b/custom-w32.el new file mode 100644 index 0000000..dcd1b43 --- /dev/null +++ b/custom-w32.el @@ -0,0 +1,41 @@ +(custom-set-variables + ;; custom-set-variables was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(TeX-auto-save t) + '(TeX-master nil) + '(TeX-parse-self t) + '(TeX-save-query nil) + '(TeX-source-correlate-method (quote synctex)) + '(TeX-source-correlate-mode t) + '(TeX-source-correlate-start-server (quote ask)) + '(current-language-environment "Russian") + '(epy-load-yasnippet-p t) + '(load-prefer-newer t) + '(rw-hunspell-default-dictionary "russian") + '(rw-hunspell-dicpath-list (quote ("/usr/share/hunspell"))) + '(rw-hunspell-make-dictionary-menu t) + '(rw-hunspell-use-rw-ispell t) + '(safe-local-variable-values + (quote + ((TeX-master . "dis") + (py-master-file . "/path/to/interactivetest.py") + (whitespace-line-column . 80) + (lexical-binding . t)))) + '(show-paren-mode t) + '(tool-bar-mode nil)) +(custom-set-faces + ;; custom-set-faces was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(default ((t (:inherit nil :stipple nil :background "grey28" :foreground "wheat1" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 158 :width normal :foundry "outline" :family "Lucida Console")))) + '(flyspell-duplicate ((t (:foreground "pale green")))) + '(flyspell-incorrect ((t (:foreground "orange red")))) + '(highlight-changes ((t (:foreground "LightGoldenrod1")))) + '(highlight-changes-delete ((t (:foreground "dark orange" :strike-through t)))) + '(linum ((t (:inherit (shadow default) :background "black" :foreground "orange")))) + '(region ((((class color) (min-colors 88) (background dark)) (:background "orange3")))) + '(tex-verbatim ((t (:family "Ubuntu Mono")))) + '(tooltip ((((class color)) (:inherit variable-pitch :background "lightyellow" :foreground "black" :height 0.5))))) diff --git a/custom.el b/custom.el new file mode 100644 index 0000000..8421f04 --- /dev/null +++ b/custom.el @@ -0,0 +1,103 @@ +(custom-set-variables + ;; custom-set-variables was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(TeX-PDF-mode t) + '(TeX-auto-save t) + '(TeX-command-extra-options "-shell-escape") + '(TeX-master nil) + '(TeX-parse-self t) + '(TeX-save-query nil) + '(TeX-source-correlate-method (quote synctex)) + '(TeX-source-correlate-mode t) + '(TeX-source-correlate-start-server (quote ask)) + '(ansi-color-faces-vector + [default bold shadow italic underline bold bold-italic bold]) + '(ansi-color-names-vector + ["#2d3743" "#ff4242" "#74af68" "#dbdb95" "#34cae2" "#008b8b" "#00ede1" "#e1e1e0"]) + '(blink-cursor-mode nil) + '(bookmark-default-file "/home/eugeneai/.emacs.d/bookmarks.bmk") + '(column-number-mode t) + '(custom-enabled-themes (quote (eugeneai-theme))) + '(custom-safe-themes + (quote + ("4cf3221feff536e2b3385209e9b9dc4c2e0818a69a1cdb4b522756bcdf4e00a4" "4aee8551b53a43a883cb0b7f3255d6859d766b6c5e14bcb01bed572fcbef4328" "024b0033a950d6a40bbbf2b1604075e6c457d40de0b52debe3ae994f88c09a4a" "5ea08b040c5515152d2bcae79a05ae5c98339b5729c359d02437bf4cc567cca5" "e200f481e31ceee929079ad8a6f629e45bdad45e5ac27101c89d55f4827071db" "e885ba299f1f0f0927bc8b10136a704c1ec05c7d04b7011559439dd9e56c56ab" "6252dbc43eefee0edc82ef000659ece4f77c4c989b4571d8d23485efc5e9ef4d" "d5af8f6ee92912a7bac8185ed447e1e825252728a1ebd1d41eb2da660d27ad62" default))) + '(default-input-method "russian-computer") + '(epy-load-yasnippet-p t) + '(fci-rule-color "#073642") + '(fringe-mode 0 nil (fringe)) + '(httpd-port 8380) + '(ispell-dictionary "english") + '(js2-basic-offset 2) + '(load-prefer-newer t) + '(markdown-command-needs-filename t) + '(minibuffer-auto-raise t) + '(minibuffer-frame-alist (quote ((width . 80) (height . 1)))) + '(python-shell-interpreter "python3") + '(rw-hunspell-default-dictionary "russian") + '(rw-hunspell-dicpath-list (quote ("/usr/share/hunspell"))) + '(rw-hunspell-make-dictionary-menu t) + '(rw-hunspell-use-rw-ispell t) + '(safe-local-variable-values + (quote + ((TeX-command-extra-options . "-shell-escape") + (TeX-auto-save . t) + (TeX-parse-self . t) + (major-mode . rst-mode) + (eval ispell-change-dictionary "ru_RU_hunspell") + (eval ispell-change-dictionary "russian") + (TeX-source-correlate-start-server) + (TeX-source-correlate-mode . 1) + (TeX-PDF-mode . 1) + (eval ispell-change-dictionary "ru-yeyo") + (ispell-local-dictionary quote ru-yeyo) + (ispell-local-dictionary . ru-yeyo) + (ispell-dictionary . ru-yeyo) + (TeX-master . t) + (ispell-dictionary . american) + (py-indent-offset . 4) + (TeX-master . "dis") + (py-master-file . "/path/to/interactivetest.py") + (whitespace-line-column . 80) + (lexical-binding . t)))) + '(show-paren-mode t) + '(text-mode-hook (quote (turn-on-flyspell text-mode-hook-identify))) + '(tool-bar-mode nil) + '(vc-annotate-background nil) + '(vc-annotate-color-map + (quote + ((20 . "#dc322f") + (40 . "#cb4b16") + (60 . "#b58900") + (80 . "#859900") + (100 . "#2aa198") + (120 . "#268bd2") + (140 . "#d33682") + (160 . "#6c71c4") + (180 . "#dc322f") + (200 . "#cb4b16") + (220 . "#b58900") + (240 . "#859900") + (260 . "#2aa198") + (280 . "#268bd2") + (300 . "#d33682") + (320 . "#6c71c4") + (340 . "#dc322f") + (360 . "#cb4b16")))) + '(vc-annotate-very-old-color nil) + '(w3-honor-stylesheets t) + '(which-function-mode nil)) +(custom-set-faces + ;; custom-set-faces was added by Custom. + ;; If you edit it by hand, you could mess it up, so be careful. + ;; Your init file should contain only one such instance. + ;; If there is more than one, they won't work right. + '(default ((t (:family "Fira Mono" :foundry "unknown" :slant normal :weight normal :height 117 :width normal)))) + '(font-latex-verbatim-face ((t (:inherit Fira\ Mono :foreground "burlywood")))) + '(js2-external-variable ((t (:foreground "orange" :slant italic)))) + '(js2-function-call ((t (:inherit default)))) + '(minibuffer-prompt ((t (:foreground "CadetBlue1")))) + '(mode-line ((t (:background "gray75" :foreground "black" :weight normal :height 0.5 :family "Droid Sans")))) + '(mode-line-highlight ((t (:background "gold")))) + '(tex-verbatim ((t (:family "Inconsolata LGC Medium"))))) diff --git a/dark-theme eugeneai-theme.el b/dark-theme eugeneai-theme.el new file mode 100644 index 0000000..74b6086 --- /dev/null +++ b/dark-theme eugeneai-theme.el @@ -0,0 +1,28 @@ +(deftheme dark-theme eugeneai + "Created 2014-03-25.") + +(custom-theme-set-variables + 'dark-theme eugeneai + '(ansi-color-names-vector ["#2d3743" "#ff4242" "#74af68" "#dbdb95" "#34cae2" "#008b8b" "#00ede1" "#e1e1e0"]) + '(custom-safe-themes (quote ("5ea08b040c5515152d2bcae79a05ae5c98339b5729c359d02437bf4cc567cca5" "e200f481e31ceee929079ad8a6f629e45bdad45e5ac27101c89d55f4827071db" "e885ba299f1f0f0927bc8b10136a704c1ec05c7d04b7011559439dd9e56c56ab" "6252dbc43eefee0edc82ef000659ece4f77c4c989b4571d8d23485efc5e9ef4d" "d5af8f6ee92912a7bac8185ed447e1e825252728a1ebd1d41eb2da660d27ad62" default))) + '(ispell-dictionary "english") + '(minibuffer-auto-raise t) + '(minibuffer-frame-alist (quote ((width . 80) (height . 1)))) + '(safe-local-variable-values (quote ((TeX-master . t) (ispell-dictionary . american) (py-indent-offset . 4) (TeX-master . "dis") (py-master-file . "/path/to/interactivetest.py") (whitespace-line-column . 80) (lexical-binding . t)))) + '(text-mode-hook (quote (turn-on-flyspell text-mode-hook-identify))) + '(which-function-mode nil) + '(tool-bar-mode nil) + '(show-paren-mode t) + '(fringe-mode 0) + '(column-number-mode t) + '(blink-cursor-mode nil)) + +(custom-theme-set-faces + 'dark-theme eugeneai + '(default ((t (:inherit nil :stipple nil :background "gray20" :foreground "wheat1" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 98 :width normal :foundry "unknown" :family "Droid Sans Mono")))) + '(minibuffer-prompt ((t (:foreground "CadetBlue1")))) + '(mode-line ((t (:background "gray75" :foreground "black" :weight normal :height 0.5 :family "Droid Sans")))) + '(mode-line-highlight ((t (:background "gold")))) + '(tex-verbatim ((t (:family "Inconsolata LGC Medium"))))) + +(provide-theme 'dark-theme eugeneai) diff --git a/CONTRIBUTORS b/epy/CONTRIBUTORS similarity index 100% rename from CONTRIBUTORS rename to epy/CONTRIBUTORS diff --git a/COPYING b/epy/COPYING similarity index 100% rename from COPYING rename to epy/COPYING diff --git a/ChangeLog b/epy/ChangeLog similarity index 100% rename from ChangeLog rename to epy/ChangeLog diff --git a/README.org b/epy/README.org similarity index 100% rename from README.org rename to epy/README.org diff --git a/doc/Usage.rst b/epy/doc/Usage.rst similarity index 100% rename from doc/Usage.rst rename to epy/doc/Usage.rst diff --git a/doc/highlight_line_ind.png b/epy/doc/highlight_line_ind.png similarity index 100% rename from doc/highlight_line_ind.png rename to epy/doc/highlight_line_ind.png diff --git a/epy-bindings.el b/epy/epy-bindings.el similarity index 100% rename from epy-bindings.el rename to epy/epy-bindings.el diff --git a/epy-completion.el b/epy/epy-completion.el similarity index 100% rename from epy-completion.el rename to epy/epy-completion.el diff --git a/epy-editing.el b/epy/epy-editing.el similarity index 100% rename from epy-editing.el rename to epy/epy-editing.el diff --git a/epy-init.el b/epy/epy-init.el similarity index 100% rename from epy-init.el rename to epy/epy-init.el diff --git a/epy-nose.el b/epy/epy-nose.el similarity index 100% rename from epy-nose.el rename to epy/epy-nose.el diff --git a/epy-python.el b/epy/epy-python.el similarity index 100% rename from epy-python.el rename to epy/epy-python.el diff --git a/epy-setup.el b/epy/epy-setup.el similarity index 100% rename from epy-setup.el rename to epy/epy-setup.el diff --git a/epy/extensions/.#a.py b/epy/extensions/.#a.py new file mode 120000 index 0000000..03c3441 --- /dev/null +++ b/epy/extensions/.#a.py @@ -0,0 +1 @@ +eugeneai@inca.irnok.net.2235:1393892527 \ No newline at end of file diff --git a/extensions/auto-complete/COPYING.FDL.txt b/epy/extensions/auto-complete/COPYING.FDL.txt similarity index 100% rename from extensions/auto-complete/COPYING.FDL.txt rename to epy/extensions/auto-complete/COPYING.FDL.txt diff --git a/extensions/auto-complete/COPYING.GPLv3.txt b/epy/extensions/auto-complete/COPYING.GPLv3.txt similarity index 100% rename from extensions/auto-complete/COPYING.GPLv3.txt rename to epy/extensions/auto-complete/COPYING.GPLv3.txt diff --git a/extensions/auto-complete/auto-complete-config.el b/epy/extensions/auto-complete/auto-complete-config.el similarity index 100% rename from extensions/auto-complete/auto-complete-config.el rename to epy/extensions/auto-complete/auto-complete-config.el diff --git a/extensions/auto-complete/auto-complete.el b/epy/extensions/auto-complete/auto-complete.el similarity index 100% rename from extensions/auto-complete/auto-complete.el rename to epy/extensions/auto-complete/auto-complete.el diff --git a/extensions/auto-complete/dict/ada-mode b/epy/extensions/auto-complete/dict/ada-mode similarity index 100% rename from extensions/auto-complete/dict/ada-mode rename to epy/extensions/auto-complete/dict/ada-mode diff --git a/extensions/auto-complete/dict/c++-mode b/epy/extensions/auto-complete/dict/c++-mode similarity index 100% rename from extensions/auto-complete/dict/c++-mode rename to epy/extensions/auto-complete/dict/c++-mode diff --git a/extensions/auto-complete/dict/c-mode b/epy/extensions/auto-complete/dict/c-mode similarity index 100% rename from extensions/auto-complete/dict/c-mode rename to epy/extensions/auto-complete/dict/c-mode diff --git a/extensions/auto-complete/dict/clojure-mode b/epy/extensions/auto-complete/dict/clojure-mode similarity index 100% rename from extensions/auto-complete/dict/clojure-mode rename to epy/extensions/auto-complete/dict/clojure-mode diff --git a/extensions/auto-complete/dict/css-mode b/epy/extensions/auto-complete/dict/css-mode similarity index 100% rename from extensions/auto-complete/dict/css-mode rename to epy/extensions/auto-complete/dict/css-mode diff --git a/extensions/auto-complete/dict/erlang-mode b/epy/extensions/auto-complete/dict/erlang-mode similarity index 100% rename from extensions/auto-complete/dict/erlang-mode rename to epy/extensions/auto-complete/dict/erlang-mode diff --git a/extensions/auto-complete/dict/java-mode b/epy/extensions/auto-complete/dict/java-mode similarity index 100% rename from extensions/auto-complete/dict/java-mode rename to epy/extensions/auto-complete/dict/java-mode diff --git a/extensions/auto-complete/dict/javascript-mode b/epy/extensions/auto-complete/dict/javascript-mode similarity index 100% rename from extensions/auto-complete/dict/javascript-mode rename to epy/extensions/auto-complete/dict/javascript-mode diff --git a/extensions/auto-complete/dict/php-mode b/epy/extensions/auto-complete/dict/php-mode similarity index 100% rename from extensions/auto-complete/dict/php-mode rename to epy/extensions/auto-complete/dict/php-mode diff --git a/extensions/auto-complete/dict/python-mode b/epy/extensions/auto-complete/dict/python-mode similarity index 100% rename from extensions/auto-complete/dict/python-mode rename to epy/extensions/auto-complete/dict/python-mode diff --git a/extensions/auto-complete/dict/ruby-mode b/epy/extensions/auto-complete/dict/ruby-mode similarity index 100% rename from extensions/auto-complete/dict/ruby-mode rename to epy/extensions/auto-complete/dict/ruby-mode diff --git a/extensions/auto-complete/dict/scheme-mode b/epy/extensions/auto-complete/dict/scheme-mode similarity index 100% rename from extensions/auto-complete/dict/scheme-mode rename to epy/extensions/auto-complete/dict/scheme-mode diff --git a/extensions/auto-complete/dict/tcl-mode b/epy/extensions/auto-complete/dict/tcl-mode similarity index 89% rename from extensions/auto-complete/dict/tcl-mode rename to epy/extensions/auto-complete/dict/tcl-mode index 07a1281..58c0255 100644 --- a/extensions/auto-complete/dict/tcl-mode +++ b/epy/extensions/auto-complete/dict/tcl-mode @@ -1,172 +1,172 @@ -after -append -apply -array -auto_execok -auto_import -auto_load -auto_load_index -auto_mkindex -auto_mkindex_old -auto_qualify -auto_reset -bell -binary -bind -bindtags -break -button -canvas -case -catch -cd -chan -checkbutton -clipboard -clock -close -concat -continue -destroy -dict -encoding -entry -eof -error -eval -event -exec -exit -expr -fblocked -fconfigure -fcopy -file -fileevent -flush -focus -font -for -foreach -format -frame -gets -glob -global -grab -grid -if -image -incr -info -interp -join -label -labelframe -lappend -lassign -lindex -linsert -list -listbox -llength -load -lower -lrange -lrepeat -lreplace -lreverse -lsearch -lset -lsort -menu -menubutton -message -namespace -open -option -pack -package -panedwindow -pid -pkg_mkIndex -place -proc -puts -pwd -radiobutton -raise -read -regexp -registry -regsub -rename -return -scale -scan -scrollbar -seek -selection -set -socket -source -spinbox -split -string -subst -switch -tclLog -tclPkgSetup -tclPkgUnknown -tcl_findLibrary -tell -text -time -tk -tk_chooseColor -tk_chooseDirectory -tk_getOpenFile -tk_getSaveFile -tk_menuSetFocus -tk_messageBox -tk_popup -tk_textCopy -tk_textCut -tk_textPaste -tkwait -toplevel -ttk::button -ttk::checkbutton -ttk::combobox -ttk::entry -ttk::focusFirst -ttk::frame -ttk::label -ttk::labelframe -ttk::menubutton -ttk::notebook -ttk::paned -ttk::panedwindow -ttk::progressbar -ttk::radiobutton -ttk::scale -ttk::scrollbar -ttk::separator -ttk::setTheme -ttk::sizegrip -ttk::style -ttk::takefocus -ttk::themes -ttk::treeview -trace -unknown -unload -unset -update -uplevel -upvar -variable -vwait -while -winfo -wm +after +append +apply +array +auto_execok +auto_import +auto_load +auto_load_index +auto_mkindex +auto_mkindex_old +auto_qualify +auto_reset +bell +binary +bind +bindtags +break +button +canvas +case +catch +cd +chan +checkbutton +clipboard +clock +close +concat +continue +destroy +dict +encoding +entry +eof +error +eval +event +exec +exit +expr +fblocked +fconfigure +fcopy +file +fileevent +flush +focus +font +for +foreach +format +frame +gets +glob +global +grab +grid +if +image +incr +info +interp +join +label +labelframe +lappend +lassign +lindex +linsert +list +listbox +llength +load +lower +lrange +lrepeat +lreplace +lreverse +lsearch +lset +lsort +menu +menubutton +message +namespace +open +option +pack +package +panedwindow +pid +pkg_mkIndex +place +proc +puts +pwd +radiobutton +raise +read +regexp +registry +regsub +rename +return +scale +scan +scrollbar +seek +selection +set +socket +source +spinbox +split +string +subst +switch +tclLog +tclPkgSetup +tclPkgUnknown +tcl_findLibrary +tell +text +time +tk +tk_chooseColor +tk_chooseDirectory +tk_getOpenFile +tk_getSaveFile +tk_menuSetFocus +tk_messageBox +tk_popup +tk_textCopy +tk_textCut +tk_textPaste +tkwait +toplevel +ttk::button +ttk::checkbutton +ttk::combobox +ttk::entry +ttk::focusFirst +ttk::frame +ttk::label +ttk::labelframe +ttk::menubutton +ttk::notebook +ttk::paned +ttk::panedwindow +ttk::progressbar +ttk::radiobutton +ttk::scale +ttk::scrollbar +ttk::separator +ttk::setTheme +ttk::sizegrip +ttk::style +ttk::takefocus +ttk::themes +ttk::treeview +trace +unknown +unload +unset +update +uplevel +upvar +variable +vwait +while +winfo +wm diff --git a/extensions/auto-complete/fuzzy.el b/epy/extensions/auto-complete/fuzzy.el similarity index 100% rename from extensions/auto-complete/fuzzy.el rename to epy/extensions/auto-complete/fuzzy.el diff --git a/extensions/auto-complete/popup.el b/epy/extensions/auto-complete/popup.el similarity index 100% rename from extensions/auto-complete/popup.el rename to epy/extensions/auto-complete/popup.el diff --git a/extensions/autopair.el b/epy/extensions/autopair.el similarity index 100% rename from extensions/autopair.el rename to epy/extensions/autopair.el diff --git a/extensions/cython-mode.el b/epy/extensions/cython-mode.el similarity index 100% rename from extensions/cython-mode.el rename to epy/extensions/cython-mode.el diff --git a/extensions/eproject/eproject-config.el b/epy/extensions/eproject/eproject-config.el similarity index 100% rename from extensions/eproject/eproject-config.el rename to epy/extensions/eproject/eproject-config.el diff --git a/extensions/yasnippet/snippets/html-mode/.yas-make-groups b/epy/extensions/eproject/eproject.cfg similarity index 100% rename from extensions/yasnippet/snippets/html-mode/.yas-make-groups rename to epy/extensions/eproject/eproject.cfg diff --git a/extensions/eproject/eproject.el b/epy/extensions/eproject/eproject.el similarity index 100% rename from extensions/eproject/eproject.el rename to epy/extensions/eproject/eproject.el diff --git a/extensions/eproject/eproject.txt b/epy/extensions/eproject/eproject.txt similarity index 100% rename from extensions/eproject/eproject.txt rename to epy/extensions/eproject/eproject.txt diff --git a/extensions/epy-project.el b/epy/extensions/epy-project.el similarity index 100% rename from extensions/epy-project.el rename to epy/extensions/epy-project.el diff --git a/extensions/flymake-cursor.el b/epy/extensions/flymake-cursor.el similarity index 100% rename from extensions/flymake-cursor.el rename to epy/extensions/flymake-cursor.el diff --git a/extensions/flymake-patch.el b/epy/extensions/flymake-patch.el similarity index 100% rename from extensions/flymake-patch.el rename to epy/extensions/flymake-patch.el diff --git a/extensions/highlight-indentation.el b/epy/extensions/highlight-indentation.el similarity index 100% rename from extensions/highlight-indentation.el rename to epy/extensions/highlight-indentation.el diff --git a/extensions/nose.el b/epy/extensions/nose.el similarity index 100% rename from extensions/nose.el rename to epy/extensions/nose.el diff --git a/extensions/open-next-line.el b/epy/extensions/open-next-line.el similarity index 100% rename from extensions/open-next-line.el rename to epy/extensions/open-next-line.el diff --git a/extensions/pymacs.el b/epy/extensions/pymacs.el similarity index 99% rename from extensions/pymacs.el rename to epy/extensions/pymacs.el index 55f41ad..a650b2a 100644 --- a/extensions/pymacs.el +++ b/epy/extensions/pymacs.el @@ -521,7 +521,7 @@ The timer is used only if `post-gc-hook' is not available.") (set-text-properties 0 (length text) nil text) (when multibyte (princ "b")) - (princ (mapconcat 'identity + (princ (mapconcat #'identity (split-string (prin1-to-string text) "\n") "\\n")) (when multibyte diff --git a/extensions/python.el b/epy/extensions/python.el similarity index 100% rename from extensions/python.el rename to epy/extensions/python.el diff --git a/extensions/smart-operator.el b/epy/extensions/smart-operator.el similarity index 100% rename from extensions/smart-operator.el rename to epy/extensions/smart-operator.el diff --git a/extensions/snippet-helpers.el b/epy/extensions/snippet-helpers.el similarity index 100% rename from extensions/snippet-helpers.el rename to epy/extensions/snippet-helpers.el diff --git a/extensions/virtualenv.el b/epy/extensions/virtualenv.el similarity index 100% rename from extensions/virtualenv.el rename to epy/extensions/virtualenv.el diff --git a/extensions/yasnippet/README b/epy/extensions/yasnippet/README similarity index 100% rename from extensions/yasnippet/README rename to epy/extensions/yasnippet/README diff --git a/extensions/yasnippet/Rakefile b/epy/extensions/yasnippet/Rakefile similarity index 100% rename from extensions/yasnippet/Rakefile rename to epy/extensions/yasnippet/Rakefile diff --git a/extensions/yasnippet/doc/changelog.html b/epy/extensions/yasnippet/doc/changelog.html similarity index 100% rename from extensions/yasnippet/doc/changelog.html rename to epy/extensions/yasnippet/doc/changelog.html diff --git a/extensions/yasnippet/doc/changelog.rst b/epy/extensions/yasnippet/doc/changelog.rst similarity index 100% rename from extensions/yasnippet/doc/changelog.rst rename to epy/extensions/yasnippet/doc/changelog.rst diff --git a/extensions/yasnippet/doc/compile-doc.py b/epy/extensions/yasnippet/doc/compile-doc.py similarity index 100% rename from extensions/yasnippet/doc/compile-doc.py rename to epy/extensions/yasnippet/doc/compile-doc.py diff --git a/extensions/yasnippet/doc/define_snippet.html b/epy/extensions/yasnippet/doc/define_snippet.html similarity index 100% rename from extensions/yasnippet/doc/define_snippet.html rename to epy/extensions/yasnippet/doc/define_snippet.html diff --git a/extensions/yasnippet/doc/define_snippet.rst b/epy/extensions/yasnippet/doc/define_snippet.rst similarity index 100% rename from extensions/yasnippet/doc/define_snippet.rst rename to epy/extensions/yasnippet/doc/define_snippet.rst diff --git a/extensions/yasnippet/doc/faq.html b/epy/extensions/yasnippet/doc/faq.html similarity index 100% rename from extensions/yasnippet/doc/faq.html rename to epy/extensions/yasnippet/doc/faq.html diff --git a/extensions/yasnippet/doc/faq.rst b/epy/extensions/yasnippet/doc/faq.rst similarity index 100% rename from extensions/yasnippet/doc/faq.rst rename to epy/extensions/yasnippet/doc/faq.rst diff --git a/extensions/yasnippet/doc/html4css1.css b/epy/extensions/yasnippet/doc/html4css1.css similarity index 100% rename from extensions/yasnippet/doc/html4css1.css rename to epy/extensions/yasnippet/doc/html4css1.css diff --git a/extensions/yasnippet/doc/images/bg-content-left.png b/epy/extensions/yasnippet/doc/images/bg-content-left.png similarity index 100% rename from extensions/yasnippet/doc/images/bg-content-left.png rename to epy/extensions/yasnippet/doc/images/bg-content-left.png diff --git a/extensions/yasnippet/doc/images/bg-content-right.png b/epy/extensions/yasnippet/doc/images/bg-content-right.png similarity index 100% rename from extensions/yasnippet/doc/images/bg-content-right.png rename to epy/extensions/yasnippet/doc/images/bg-content-right.png diff --git a/extensions/yasnippet/doc/images/bg-content.png b/epy/extensions/yasnippet/doc/images/bg-content.png similarity index 100% rename from extensions/yasnippet/doc/images/bg-content.png rename to epy/extensions/yasnippet/doc/images/bg-content.png diff --git a/extensions/yasnippet/doc/images/bg-navigation-item-hover.png b/epy/extensions/yasnippet/doc/images/bg-navigation-item-hover.png similarity index 100% rename from extensions/yasnippet/doc/images/bg-navigation-item-hover.png rename to epy/extensions/yasnippet/doc/images/bg-navigation-item-hover.png diff --git a/extensions/yasnippet/doc/images/bg-navigation-item.png b/epy/extensions/yasnippet/doc/images/bg-navigation-item.png similarity index 100% rename from extensions/yasnippet/doc/images/bg-navigation-item.png rename to epy/extensions/yasnippet/doc/images/bg-navigation-item.png diff --git a/extensions/yasnippet/doc/images/bg-navigation.png b/epy/extensions/yasnippet/doc/images/bg-navigation.png similarity index 100% rename from extensions/yasnippet/doc/images/bg-navigation.png rename to epy/extensions/yasnippet/doc/images/bg-navigation.png diff --git a/extensions/yasnippet/doc/images/body.png b/epy/extensions/yasnippet/doc/images/body.png similarity index 100% rename from extensions/yasnippet/doc/images/body.png rename to epy/extensions/yasnippet/doc/images/body.png diff --git a/extensions/yasnippet/doc/images/customization-group.png b/epy/extensions/yasnippet/doc/images/customization-group.png similarity index 100% rename from extensions/yasnippet/doc/images/customization-group.png rename to epy/extensions/yasnippet/doc/images/customization-group.png diff --git a/extensions/yasnippet/doc/images/dropdown-menu.png b/epy/extensions/yasnippet/doc/images/dropdown-menu.png similarity index 100% rename from extensions/yasnippet/doc/images/dropdown-menu.png rename to epy/extensions/yasnippet/doc/images/dropdown-menu.png diff --git a/extensions/yasnippet/doc/images/external.png b/epy/extensions/yasnippet/doc/images/external.png similarity index 100% rename from extensions/yasnippet/doc/images/external.png rename to epy/extensions/yasnippet/doc/images/external.png diff --git a/extensions/yasnippet/doc/images/ido-menu.png b/epy/extensions/yasnippet/doc/images/ido-menu.png similarity index 100% rename from extensions/yasnippet/doc/images/ido-menu.png rename to epy/extensions/yasnippet/doc/images/ido-menu.png diff --git a/extensions/yasnippet/doc/images/menu-1.png b/epy/extensions/yasnippet/doc/images/menu-1.png similarity index 100% rename from extensions/yasnippet/doc/images/menu-1.png rename to epy/extensions/yasnippet/doc/images/menu-1.png diff --git a/extensions/yasnippet/doc/images/menu-2.png b/epy/extensions/yasnippet/doc/images/menu-2.png similarity index 100% rename from extensions/yasnippet/doc/images/menu-2.png rename to epy/extensions/yasnippet/doc/images/menu-2.png diff --git a/extensions/yasnippet/doc/images/menu-groups.png b/epy/extensions/yasnippet/doc/images/menu-groups.png similarity index 100% rename from extensions/yasnippet/doc/images/menu-groups.png rename to epy/extensions/yasnippet/doc/images/menu-groups.png diff --git a/extensions/yasnippet/doc/images/menu-parent.png b/epy/extensions/yasnippet/doc/images/menu-parent.png similarity index 100% rename from extensions/yasnippet/doc/images/menu-parent.png rename to epy/extensions/yasnippet/doc/images/menu-parent.png diff --git a/extensions/yasnippet/doc/images/minor-mode-indicator.png b/epy/extensions/yasnippet/doc/images/minor-mode-indicator.png similarity index 100% rename from extensions/yasnippet/doc/images/minor-mode-indicator.png rename to epy/extensions/yasnippet/doc/images/minor-mode-indicator.png diff --git a/extensions/yasnippet/doc/images/x-menu.png b/epy/extensions/yasnippet/doc/images/x-menu.png similarity index 100% rename from extensions/yasnippet/doc/images/x-menu.png rename to epy/extensions/yasnippet/doc/images/x-menu.png diff --git a/extensions/yasnippet/doc/index.html b/epy/extensions/yasnippet/doc/index.html similarity index 100% rename from extensions/yasnippet/doc/index.html rename to epy/extensions/yasnippet/doc/index.html diff --git a/extensions/yasnippet/doc/index.rst b/epy/extensions/yasnippet/doc/index.rst similarity index 100% rename from extensions/yasnippet/doc/index.rst rename to epy/extensions/yasnippet/doc/index.rst diff --git a/extensions/yasnippet/doc/snippet-development.html b/epy/extensions/yasnippet/doc/snippet-development.html similarity index 100% rename from extensions/yasnippet/doc/snippet-development.html rename to epy/extensions/yasnippet/doc/snippet-development.html diff --git a/extensions/yasnippet/doc/snippet-development.rst b/epy/extensions/yasnippet/doc/snippet-development.rst similarity index 100% rename from extensions/yasnippet/doc/snippet-development.rst rename to epy/extensions/yasnippet/doc/snippet-development.rst diff --git a/extensions/yasnippet/doc/snippet-expansion.html b/epy/extensions/yasnippet/doc/snippet-expansion.html similarity index 100% rename from extensions/yasnippet/doc/snippet-expansion.html rename to epy/extensions/yasnippet/doc/snippet-expansion.html diff --git a/extensions/yasnippet/doc/snippet-expansion.rst b/epy/extensions/yasnippet/doc/snippet-expansion.rst similarity index 100% rename from extensions/yasnippet/doc/snippet-expansion.rst rename to epy/extensions/yasnippet/doc/snippet-expansion.rst diff --git a/extensions/yasnippet/doc/snippet-menu.html b/epy/extensions/yasnippet/doc/snippet-menu.html similarity index 100% rename from extensions/yasnippet/doc/snippet-menu.html rename to epy/extensions/yasnippet/doc/snippet-menu.html diff --git a/extensions/yasnippet/doc/snippet-menu.rst b/epy/extensions/yasnippet/doc/snippet-menu.rst similarity index 100% rename from extensions/yasnippet/doc/snippet-menu.rst rename to epy/extensions/yasnippet/doc/snippet-menu.rst diff --git a/extensions/yasnippet/doc/snippet-organization.html b/epy/extensions/yasnippet/doc/snippet-organization.html similarity index 100% rename from extensions/yasnippet/doc/snippet-organization.html rename to epy/extensions/yasnippet/doc/snippet-organization.html diff --git a/extensions/yasnippet/doc/snippet-organization.rst b/epy/extensions/yasnippet/doc/snippet-organization.rst similarity index 100% rename from extensions/yasnippet/doc/snippet-organization.rst rename to epy/extensions/yasnippet/doc/snippet-organization.rst diff --git a/extensions/yasnippet/doc/styles.css b/epy/extensions/yasnippet/doc/styles.css similarity index 100% rename from extensions/yasnippet/doc/styles.css rename to epy/extensions/yasnippet/doc/styles.css diff --git a/extensions/yasnippet/doc/template.txt b/epy/extensions/yasnippet/doc/template.txt similarity index 100% rename from extensions/yasnippet/doc/template.txt rename to epy/extensions/yasnippet/doc/template.txt diff --git a/extensions/yasnippet/dropdown-list.el b/epy/extensions/yasnippet/dropdown-list.el similarity index 100% rename from extensions/yasnippet/dropdown-list.el rename to epy/extensions/yasnippet/dropdown-list.el diff --git a/extensions/yasnippet/extras/imported/html-mode/.yas-setup.el b/epy/extensions/yasnippet/extras/imported/html-mode/.yas-setup.el similarity index 100% rename from extensions/yasnippet/extras/imported/html-mode/.yas-setup.el rename to epy/extensions/yasnippet/extras/imported/html-mode/.yas-setup.el diff --git a/extensions/yasnippet/extras/imported/rails-mode/.yas-setup.el b/epy/extensions/yasnippet/extras/imported/rails-mode/.yas-setup.el similarity index 100% rename from extensions/yasnippet/extras/imported/rails-mode/.yas-setup.el rename to epy/extensions/yasnippet/extras/imported/rails-mode/.yas-setup.el diff --git a/extensions/yasnippet/extras/imported/ruby-mode/.yas-setup.el b/epy/extensions/yasnippet/extras/imported/ruby-mode/.yas-setup.el similarity index 100% rename from extensions/yasnippet/extras/imported/ruby-mode/.yas-setup.el rename to epy/extensions/yasnippet/extras/imported/ruby-mode/.yas-setup.el diff --git a/extensions/yasnippet/extras/textmate_import.rb b/epy/extensions/yasnippet/extras/textmate_import.rb similarity index 100% rename from extensions/yasnippet/extras/textmate_import.rb rename to epy/extensions/yasnippet/extras/textmate_import.rb diff --git a/extensions/yasnippet/snippets/c++-mode/.yas-parents b/epy/extensions/yasnippet/snippets/c++-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/c++-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/c++-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/c++-mode/beginend b/epy/extensions/yasnippet/snippets/c++-mode/beginend similarity index 100% rename from extensions/yasnippet/snippets/c++-mode/beginend rename to epy/extensions/yasnippet/snippets/c++-mode/beginend diff --git a/extensions/yasnippet/snippets/c++-mode/class b/epy/extensions/yasnippet/snippets/c++-mode/class similarity index 100% rename from extensions/yasnippet/snippets/c++-mode/class rename to epy/extensions/yasnippet/snippets/c++-mode/class diff --git a/extensions/yasnippet/snippets/c++-mode/ns b/epy/extensions/yasnippet/snippets/c++-mode/ns similarity index 100% rename from extensions/yasnippet/snippets/c++-mode/ns rename to epy/extensions/yasnippet/snippets/c++-mode/ns diff --git a/extensions/yasnippet/snippets/c++-mode/template b/epy/extensions/yasnippet/snippets/c++-mode/template similarity index 100% rename from extensions/yasnippet/snippets/c++-mode/template rename to epy/extensions/yasnippet/snippets/c++-mode/template diff --git a/extensions/yasnippet/snippets/c++-mode/using b/epy/extensions/yasnippet/snippets/c++-mode/using similarity index 100% rename from extensions/yasnippet/snippets/c++-mode/using rename to epy/extensions/yasnippet/snippets/c++-mode/using diff --git a/extensions/yasnippet/snippets/c-mode/.yas-parents b/epy/extensions/yasnippet/snippets/c-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/c-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/c-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/c-mode/fopen b/epy/extensions/yasnippet/snippets/c-mode/fopen similarity index 100% rename from extensions/yasnippet/snippets/c-mode/fopen rename to epy/extensions/yasnippet/snippets/c-mode/fopen diff --git a/extensions/yasnippet/snippets/c-mode/printf b/epy/extensions/yasnippet/snippets/c-mode/printf similarity index 100% rename from extensions/yasnippet/snippets/c-mode/printf rename to epy/extensions/yasnippet/snippets/c-mode/printf diff --git a/extensions/yasnippet/snippets/cc-mode/.yas-parents b/epy/extensions/yasnippet/snippets/cc-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/cc-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/cc-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/cc-mode/do b/epy/extensions/yasnippet/snippets/cc-mode/do similarity index 100% rename from extensions/yasnippet/snippets/cc-mode/do rename to epy/extensions/yasnippet/snippets/cc-mode/do diff --git a/extensions/yasnippet/snippets/cc-mode/for b/epy/extensions/yasnippet/snippets/cc-mode/for similarity index 100% rename from extensions/yasnippet/snippets/cc-mode/for rename to epy/extensions/yasnippet/snippets/cc-mode/for diff --git a/extensions/yasnippet/snippets/cc-mode/if b/epy/extensions/yasnippet/snippets/cc-mode/if similarity index 100% rename from extensions/yasnippet/snippets/cc-mode/if rename to epy/extensions/yasnippet/snippets/cc-mode/if diff --git a/extensions/yasnippet/snippets/cc-mode/inc b/epy/extensions/yasnippet/snippets/cc-mode/inc similarity index 100% rename from extensions/yasnippet/snippets/cc-mode/inc rename to epy/extensions/yasnippet/snippets/cc-mode/inc diff --git a/extensions/yasnippet/snippets/cc-mode/inc.1 b/epy/extensions/yasnippet/snippets/cc-mode/inc.1 similarity index 100% rename from extensions/yasnippet/snippets/cc-mode/inc.1 rename to epy/extensions/yasnippet/snippets/cc-mode/inc.1 diff --git a/extensions/yasnippet/snippets/cc-mode/main b/epy/extensions/yasnippet/snippets/cc-mode/main similarity index 100% rename from extensions/yasnippet/snippets/cc-mode/main rename to epy/extensions/yasnippet/snippets/cc-mode/main diff --git a/extensions/yasnippet/snippets/cc-mode/once b/epy/extensions/yasnippet/snippets/cc-mode/once similarity index 100% rename from extensions/yasnippet/snippets/cc-mode/once rename to epy/extensions/yasnippet/snippets/cc-mode/once diff --git a/extensions/yasnippet/snippets/cc-mode/struct b/epy/extensions/yasnippet/snippets/cc-mode/struct similarity index 100% rename from extensions/yasnippet/snippets/cc-mode/struct rename to epy/extensions/yasnippet/snippets/cc-mode/struct diff --git a/extensions/yasnippet/snippets/cperl-mode/.yas-parents b/epy/extensions/yasnippet/snippets/cperl-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/cperl-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/cperl-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/csharp-mode/.yas-parents b/epy/extensions/yasnippet/snippets/csharp-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/csharp-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/csharp-mode/attrib b/epy/extensions/yasnippet/snippets/csharp-mode/attrib similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/attrib rename to epy/extensions/yasnippet/snippets/csharp-mode/attrib diff --git a/extensions/yasnippet/snippets/csharp-mode/attrib.1 b/epy/extensions/yasnippet/snippets/csharp-mode/attrib.1 similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/attrib.1 rename to epy/extensions/yasnippet/snippets/csharp-mode/attrib.1 diff --git a/extensions/yasnippet/snippets/csharp-mode/attrib.2 b/epy/extensions/yasnippet/snippets/csharp-mode/attrib.2 similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/attrib.2 rename to epy/extensions/yasnippet/snippets/csharp-mode/attrib.2 diff --git a/extensions/yasnippet/snippets/csharp-mode/class b/epy/extensions/yasnippet/snippets/csharp-mode/class similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/class rename to epy/extensions/yasnippet/snippets/csharp-mode/class diff --git a/extensions/yasnippet/snippets/csharp-mode/comment b/epy/extensions/yasnippet/snippets/csharp-mode/comment similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/comment rename to epy/extensions/yasnippet/snippets/csharp-mode/comment diff --git a/extensions/yasnippet/snippets/csharp-mode/comment.1 b/epy/extensions/yasnippet/snippets/csharp-mode/comment.1 similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/comment.1 rename to epy/extensions/yasnippet/snippets/csharp-mode/comment.1 diff --git a/extensions/yasnippet/snippets/csharp-mode/comment.2 b/epy/extensions/yasnippet/snippets/csharp-mode/comment.2 similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/comment.2 rename to epy/extensions/yasnippet/snippets/csharp-mode/comment.2 diff --git a/extensions/yasnippet/snippets/csharp-mode/comment.3 b/epy/extensions/yasnippet/snippets/csharp-mode/comment.3 similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/comment.3 rename to epy/extensions/yasnippet/snippets/csharp-mode/comment.3 diff --git a/extensions/yasnippet/snippets/csharp-mode/method b/epy/extensions/yasnippet/snippets/csharp-mode/method similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/method rename to epy/extensions/yasnippet/snippets/csharp-mode/method diff --git a/extensions/yasnippet/snippets/csharp-mode/namespace b/epy/extensions/yasnippet/snippets/csharp-mode/namespace similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/namespace rename to epy/extensions/yasnippet/snippets/csharp-mode/namespace diff --git a/extensions/yasnippet/snippets/csharp-mode/prop b/epy/extensions/yasnippet/snippets/csharp-mode/prop similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/prop rename to epy/extensions/yasnippet/snippets/csharp-mode/prop diff --git a/extensions/yasnippet/snippets/csharp-mode/region b/epy/extensions/yasnippet/snippets/csharp-mode/region similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/region rename to epy/extensions/yasnippet/snippets/csharp-mode/region diff --git a/extensions/yasnippet/snippets/csharp-mode/using b/epy/extensions/yasnippet/snippets/csharp-mode/using similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/using rename to epy/extensions/yasnippet/snippets/csharp-mode/using diff --git a/extensions/yasnippet/snippets/csharp-mode/using.1 b/epy/extensions/yasnippet/snippets/csharp-mode/using.1 similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/using.1 rename to epy/extensions/yasnippet/snippets/csharp-mode/using.1 diff --git a/extensions/yasnippet/snippets/csharp-mode/using.2 b/epy/extensions/yasnippet/snippets/csharp-mode/using.2 similarity index 100% rename from extensions/yasnippet/snippets/csharp-mode/using.2 rename to epy/extensions/yasnippet/snippets/csharp-mode/using.2 diff --git a/extensions/yasnippet/snippets/css-mode/.yas-parents b/epy/extensions/yasnippet/snippets/css-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/css-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/css-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/css-mode/bg b/epy/extensions/yasnippet/snippets/css-mode/bg similarity index 100% rename from extensions/yasnippet/snippets/css-mode/bg rename to epy/extensions/yasnippet/snippets/css-mode/bg diff --git a/extensions/yasnippet/snippets/css-mode/bg.1 b/epy/extensions/yasnippet/snippets/css-mode/bg.1 similarity index 100% rename from extensions/yasnippet/snippets/css-mode/bg.1 rename to epy/extensions/yasnippet/snippets/css-mode/bg.1 diff --git a/extensions/yasnippet/snippets/css-mode/bor b/epy/extensions/yasnippet/snippets/css-mode/bor similarity index 100% rename from extensions/yasnippet/snippets/css-mode/bor rename to epy/extensions/yasnippet/snippets/css-mode/bor diff --git a/extensions/yasnippet/snippets/css-mode/cl b/epy/extensions/yasnippet/snippets/css-mode/cl similarity index 100% rename from extensions/yasnippet/snippets/css-mode/cl rename to epy/extensions/yasnippet/snippets/css-mode/cl diff --git a/extensions/yasnippet/snippets/css-mode/disp.block b/epy/extensions/yasnippet/snippets/css-mode/disp.block similarity index 100% rename from extensions/yasnippet/snippets/css-mode/disp.block rename to epy/extensions/yasnippet/snippets/css-mode/disp.block diff --git a/extensions/yasnippet/snippets/css-mode/disp.inline b/epy/extensions/yasnippet/snippets/css-mode/disp.inline similarity index 100% rename from extensions/yasnippet/snippets/css-mode/disp.inline rename to epy/extensions/yasnippet/snippets/css-mode/disp.inline diff --git a/extensions/yasnippet/snippets/css-mode/disp.none b/epy/extensions/yasnippet/snippets/css-mode/disp.none similarity index 100% rename from extensions/yasnippet/snippets/css-mode/disp.none rename to epy/extensions/yasnippet/snippets/css-mode/disp.none diff --git a/extensions/yasnippet/snippets/css-mode/ff b/epy/extensions/yasnippet/snippets/css-mode/ff similarity index 100% rename from extensions/yasnippet/snippets/css-mode/ff rename to epy/extensions/yasnippet/snippets/css-mode/ff diff --git a/extensions/yasnippet/snippets/css-mode/fs b/epy/extensions/yasnippet/snippets/css-mode/fs similarity index 100% rename from extensions/yasnippet/snippets/css-mode/fs rename to epy/extensions/yasnippet/snippets/css-mode/fs diff --git a/extensions/yasnippet/snippets/css-mode/mar.bottom b/epy/extensions/yasnippet/snippets/css-mode/mar.bottom similarity index 100% rename from extensions/yasnippet/snippets/css-mode/mar.bottom rename to epy/extensions/yasnippet/snippets/css-mode/mar.bottom diff --git a/extensions/yasnippet/snippets/css-mode/mar.left b/epy/extensions/yasnippet/snippets/css-mode/mar.left similarity index 100% rename from extensions/yasnippet/snippets/css-mode/mar.left rename to epy/extensions/yasnippet/snippets/css-mode/mar.left diff --git a/extensions/yasnippet/snippets/css-mode/mar.mar b/epy/extensions/yasnippet/snippets/css-mode/mar.mar similarity index 100% rename from extensions/yasnippet/snippets/css-mode/mar.mar rename to epy/extensions/yasnippet/snippets/css-mode/mar.mar diff --git a/extensions/yasnippet/snippets/css-mode/mar.margin b/epy/extensions/yasnippet/snippets/css-mode/mar.margin similarity index 100% rename from extensions/yasnippet/snippets/css-mode/mar.margin rename to epy/extensions/yasnippet/snippets/css-mode/mar.margin diff --git a/extensions/yasnippet/snippets/css-mode/mar.right b/epy/extensions/yasnippet/snippets/css-mode/mar.right similarity index 100% rename from extensions/yasnippet/snippets/css-mode/mar.right rename to epy/extensions/yasnippet/snippets/css-mode/mar.right diff --git a/extensions/yasnippet/snippets/css-mode/mar.top b/epy/extensions/yasnippet/snippets/css-mode/mar.top similarity index 100% rename from extensions/yasnippet/snippets/css-mode/mar.top rename to epy/extensions/yasnippet/snippets/css-mode/mar.top diff --git a/extensions/yasnippet/snippets/css-mode/pad.bottom b/epy/extensions/yasnippet/snippets/css-mode/pad.bottom similarity index 100% rename from extensions/yasnippet/snippets/css-mode/pad.bottom rename to epy/extensions/yasnippet/snippets/css-mode/pad.bottom diff --git a/extensions/yasnippet/snippets/css-mode/pad.left b/epy/extensions/yasnippet/snippets/css-mode/pad.left similarity index 100% rename from extensions/yasnippet/snippets/css-mode/pad.left rename to epy/extensions/yasnippet/snippets/css-mode/pad.left diff --git a/extensions/yasnippet/snippets/css-mode/pad.pad b/epy/extensions/yasnippet/snippets/css-mode/pad.pad similarity index 100% rename from extensions/yasnippet/snippets/css-mode/pad.pad rename to epy/extensions/yasnippet/snippets/css-mode/pad.pad diff --git a/extensions/yasnippet/snippets/css-mode/pad.padding b/epy/extensions/yasnippet/snippets/css-mode/pad.padding similarity index 100% rename from extensions/yasnippet/snippets/css-mode/pad.padding rename to epy/extensions/yasnippet/snippets/css-mode/pad.padding diff --git a/extensions/yasnippet/snippets/css-mode/pad.right b/epy/extensions/yasnippet/snippets/css-mode/pad.right similarity index 100% rename from extensions/yasnippet/snippets/css-mode/pad.right rename to epy/extensions/yasnippet/snippets/css-mode/pad.right diff --git a/extensions/yasnippet/snippets/css-mode/pad.top b/epy/extensions/yasnippet/snippets/css-mode/pad.top similarity index 100% rename from extensions/yasnippet/snippets/css-mode/pad.top rename to epy/extensions/yasnippet/snippets/css-mode/pad.top diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/.read_me b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/.read_me similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/.read_me rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/.read_me diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/.yas-parents b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/add-hook.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/add-hook.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/add-hook.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/add-hook.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/and.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/and.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/and.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/and.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/append.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/append.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/append.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/append.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/apply.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/apply.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/apply.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/apply.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/aref.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/aref.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/aref.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/aref.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/aset.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/aset.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/aset.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/aset.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/assq.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/assq.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/assq.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/assq.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/autoload.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/autoload.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/autoload.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/autoload.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/backward-char.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/backward-char.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/backward-char.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/backward-char.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/beginning-of-line.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/beginning-of-line.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/beginning-of-line.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/beginning-of-line.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/bounds-of-thing-at-point.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/bounds-of-thing-at-point.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/bounds-of-thing-at-point.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/bounds-of-thing-at-point.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/buffer-file-name.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/buffer-file-name.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/buffer-file-name.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/buffer-file-name.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/buffer-modified-p.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/buffer-modified-p.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/buffer-modified-p.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/buffer-modified-p.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/buffer-substring-no-properties.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/buffer-substring-no-properties.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/buffer-substring-no-properties.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/buffer-substring-no-properties.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/buffer-substring.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/buffer-substring.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/buffer-substring.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/buffer-substring.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/car.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/car.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/car.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/car.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/cdr.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/cdr.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/cdr.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/cdr.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/concat.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/concat.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/concat.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/concat.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/cond.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/cond.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/cond.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/cond.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/condition-case.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/condition-case.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/condition-case.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/condition-case.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/cons.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/cons.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/cons.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/cons.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/consp.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/consp.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/consp.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/consp.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/copy-directory.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/copy-directory.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/copy-directory.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/copy-directory.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/copy-file.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/copy-file.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/copy-file.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/copy-file.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/current-buffer.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/current-buffer.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/current-buffer.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/current-buffer.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/custom-autoload.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/custom-autoload.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/custom-autoload.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/custom-autoload.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/defalias.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/defalias.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/defalias.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/defalias.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/defcustom.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/defcustom.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/defcustom.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/defcustom.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/define-key.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/define-key.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/define-key.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/define-key.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/defsubst.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/defsubst.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/defsubst.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/defsubst.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/defun b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/defun similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/defun rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/defun diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/defun.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/defun.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/defun.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/defun.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/defvar.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/defvar.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/defvar.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/defvar.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/delete-char.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/delete-char.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/delete-char.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/delete-char.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/delete-directory.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/delete-directory.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/delete-directory.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/delete-directory.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/delete-file.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/delete-file.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/delete-file.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/delete-file.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/delete-region.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/delete-region.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/delete-region.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/delete-region.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/directory-files.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/directory-files.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/directory-files.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/directory-files.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/dired.process_marked b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/dired.process_marked similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/dired.process_marked rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/dired.process_marked diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/dolist.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/dolist.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/dolist.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/dolist.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/end-of-line.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/end-of-line.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/end-of-line.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/end-of-line.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/eq.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/eq.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/eq.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/eq.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/equal.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/equal.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/equal.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/equal.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/error.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/error.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/error.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/error.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/expand-file-name.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/expand-file-name.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/expand-file-name.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/expand-file-name.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/f.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/f.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/f.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/f.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/fboundp.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/fboundp.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/fboundp.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/fboundp.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/file-name-directory.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/file-name-directory.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/file-name-directory.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/file-name-directory.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/file-name-extension.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/file-name-extension.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/file-name-extension.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/file-name-extension.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/file-name-nondirectory.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/file-name-nondirectory.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/file-name-nondirectory.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/file-name-nondirectory.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/file-name-sans-extension.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/file-name-sans-extension.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/file-name-sans-extension.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/file-name-sans-extension.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/file-relative-name.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/file-relative-name.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/file-relative-name.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/file-relative-name.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/file.process b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/file.process similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/file.process rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/file.process diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/file.read-lines b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/file.read-lines similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/file.read-lines rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/file.read-lines diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/find-file.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/find-file.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/find-file.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/find-file.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/find-replace b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/find-replace similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/find-replace rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/find-replace diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/format.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/format.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/format.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/format.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/forward-char.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/forward-char.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/forward-char.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/forward-char.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/forward-line.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/forward-line.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/forward-line.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/forward-line.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/funcall.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/funcall.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/funcall.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/funcall.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/function.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/function.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/function.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/function.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/get.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/get.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/get.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/get.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/global-set-key.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/global-set-key.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/global-set-key.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/global-set-key.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/goto-char.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/goto-char.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/goto-char.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/goto-char.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/grabstring b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/grabstring similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/grabstring rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/grabstring diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/grabthing b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/grabthing similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/grabthing rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/grabthing diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/if.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/if.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/if.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/if.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/insert-file-contents.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/insert-file-contents.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/insert-file-contents.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/insert-file-contents.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/insert.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/insert.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/insert.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/insert.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/interactive.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/interactive.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/interactive.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/interactive.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/kbd.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/kbd.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/kbd.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/kbd.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/kill-buffer.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/kill-buffer.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/kill-buffer.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/kill-buffer.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/lambda.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/lambda.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/lambda.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/lambda.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/length.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/length.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/length.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/length.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/let.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/let.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/let.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/let.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/line-beginning-position.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/line-beginning-position.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/line-beginning-position.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/line-beginning-position.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/line-end-position.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/line-end-position.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/line-end-position.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/line-end-position.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/list.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/list.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/list.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/list.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/looking-at.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/looking-at.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/looking-at.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/looking-at.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/make-directory.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/make-directory.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/make-directory.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/make-directory.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/make-local-variable.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/make-local-variable.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/make-local-variable.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/make-local-variable.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/mapc.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/mapc.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/mapc.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/mapc.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/mapcar.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/mapcar.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/mapcar.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/mapcar.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/match-beginning.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/match-beginning.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/match-beginning.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/match-beginning.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/match-end.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/match-end.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/match-end.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/match-end.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/match-string.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/match-string.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/match-string.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/match-string.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/memq.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/memq.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/memq.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/memq.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/message.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/message.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/message.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/message.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/not.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/not.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/not.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/not.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/nth.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/nth.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/nth.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/nth.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/null.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/null.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/null.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/null.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/number-to-string.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/number-to-string.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/number-to-string.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/number-to-string.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/or.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/or.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/or.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/or.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/point-max.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/point-max.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/point-max.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/point-max.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/point-min.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/point-min.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/point-min.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/point-min.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/point.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/point.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/point.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/point.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/princ.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/princ.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/princ.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/princ.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/print.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/print.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/print.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/print.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/progn.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/progn.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/progn.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/progn.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/push.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/push.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/push.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/push.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/put.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/put.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/put.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/put.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/re-search-backward.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/re-search-backward.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/re-search-backward.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/re-search-backward.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/re-search-forward.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/re-search-forward.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/re-search-forward.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/re-search-forward.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/region-active-p.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/region-active-p.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/region-active-p.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/region-active-p.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/region-beginning.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/region-beginning.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/region-beginning.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/region-beginning.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/region-end.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/region-end.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/region-end.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/region-end.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/rename-file.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/rename-file.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/rename-file.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/rename-file.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/repeat.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/repeat.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/repeat.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/repeat.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/replace-regexp-in-string.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/replace-regexp-in-string.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/replace-regexp-in-string.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/replace-regexp-in-string.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/replace-regexp.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/replace-regexp.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/replace-regexp.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/replace-regexp.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/require.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/require.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/require.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/require.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/save-buffer.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/save-buffer.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/save-buffer.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/save-buffer.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/save-excursion.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/save-excursion.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/save-excursion.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/save-excursion.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/search-backward-regexp.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/search-backward-regexp.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/search-backward-regexp.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/search-backward-regexp.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/search-backward.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/search-backward.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/search-backward.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/search-backward.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/search-forward-regexp.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/search-forward-regexp.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/search-forward-regexp.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/search-forward-regexp.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/search-forward.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/search-forward.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/search-forward.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/search-forward.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/set-buffer.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/set-buffer.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/set-buffer.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/set-buffer.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/set-file-modes.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/set-file-modes.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/set-file-modes.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/set-file-modes.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/set-mark.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/set-mark.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/set-mark.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/set-mark.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/set.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/set.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/set.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/set.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/setq.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/setq.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/setq.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/setq.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/skip-chars-backward.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/skip-chars-backward.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/skip-chars-backward.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/skip-chars-backward.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/skip-chars-forward.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/skip-chars-forward.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/skip-chars-forward.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/skip-chars-forward.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/split-string.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/split-string.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/split-string.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/split-string.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/string-match.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/string-match.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/string-match.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/string-match.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/string-to-number.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/string-to-number.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/string-to-number.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/string-to-number.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/string.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/string.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/string.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/string.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/string=.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/string=.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/string=.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/string=.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/stringp.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/stringp.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/stringp.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/stringp.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/substring.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/substring.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/substring.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/substring.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/thing-at-point.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/thing-at-point.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/thing-at-point.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/thing-at-point.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/traverse_dir b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/traverse_dir similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/traverse_dir rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/traverse_dir diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/unless.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/unless.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/unless.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/unless.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/vector.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/vector.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/vector.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/vector.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/when.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/when.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/when.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/when.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/while.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/while.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/while.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/while.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/widget-get.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/widget-get.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/widget-get.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/widget-get.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/with-current-buffer.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/with-current-buffer.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/with-current-buffer.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/with-current-buffer.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/word-or-region b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/word-or-region similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/word-or-region rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/word-or-region diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/x-dired.process_marked.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-dired.process_marked.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/x-dired.process_marked.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-dired.process_marked.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/x-file.process.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-file.process.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/x-file.process.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-file.process.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/x-file.read-lines.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-file.read-lines.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/x-file.read-lines.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-file.read-lines.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/x-find-replace.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-find-replace.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/x-find-replace.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-find-replace.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/x-grabstring.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-grabstring.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/x-grabstring.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-grabstring.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/x-grabthing.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-grabthing.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/x-grabthing.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-grabthing.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/x-traverse_dir.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-traverse_dir.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/x-traverse_dir.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-traverse_dir.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/x-word-or-region.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-word-or-region.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/x-word-or-region.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/x-word-or-region.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/y-or-n-p.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/y-or-n-p.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/y-or-n-p.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/y-or-n-p.yasnippet diff --git a/extensions/yasnippet/snippets/emacs-lisp-mode/yes-or-no-p.yasnippet b/epy/extensions/yasnippet/snippets/emacs-lisp-mode/yes-or-no-p.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/emacs-lisp-mode/yes-or-no-p.yasnippet rename to epy/extensions/yasnippet/snippets/emacs-lisp-mode/yes-or-no-p.yasnippet diff --git a/extensions/yasnippet/snippets/erlang-mode/.yas-parents b/epy/extensions/yasnippet/snippets/erlang-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/erlang-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/erlang-mode/after b/epy/extensions/yasnippet/snippets/erlang-mode/after similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/after rename to epy/extensions/yasnippet/snippets/erlang-mode/after diff --git a/extensions/yasnippet/snippets/erlang-mode/begin b/epy/extensions/yasnippet/snippets/erlang-mode/begin similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/begin rename to epy/extensions/yasnippet/snippets/erlang-mode/begin diff --git a/extensions/yasnippet/snippets/erlang-mode/beh b/epy/extensions/yasnippet/snippets/erlang-mode/beh similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/beh rename to epy/extensions/yasnippet/snippets/erlang-mode/beh diff --git a/extensions/yasnippet/snippets/erlang-mode/case b/epy/extensions/yasnippet/snippets/erlang-mode/case similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/case rename to epy/extensions/yasnippet/snippets/erlang-mode/case diff --git a/extensions/yasnippet/snippets/erlang-mode/compile b/epy/extensions/yasnippet/snippets/erlang-mode/compile similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/compile rename to epy/extensions/yasnippet/snippets/erlang-mode/compile diff --git a/extensions/yasnippet/snippets/erlang-mode/def b/epy/extensions/yasnippet/snippets/erlang-mode/def similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/def rename to epy/extensions/yasnippet/snippets/erlang-mode/def diff --git a/extensions/yasnippet/snippets/erlang-mode/exp b/epy/extensions/yasnippet/snippets/erlang-mode/exp similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/exp rename to epy/extensions/yasnippet/snippets/erlang-mode/exp diff --git a/extensions/yasnippet/snippets/erlang-mode/fun b/epy/extensions/yasnippet/snippets/erlang-mode/fun similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/fun rename to epy/extensions/yasnippet/snippets/erlang-mode/fun diff --git a/extensions/yasnippet/snippets/erlang-mode/if b/epy/extensions/yasnippet/snippets/erlang-mode/if similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/if rename to epy/extensions/yasnippet/snippets/erlang-mode/if diff --git a/extensions/yasnippet/snippets/erlang-mode/ifdef b/epy/extensions/yasnippet/snippets/erlang-mode/ifdef similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/ifdef rename to epy/extensions/yasnippet/snippets/erlang-mode/ifdef diff --git a/extensions/yasnippet/snippets/erlang-mode/ifndef b/epy/extensions/yasnippet/snippets/erlang-mode/ifndef similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/ifndef rename to epy/extensions/yasnippet/snippets/erlang-mode/ifndef diff --git a/extensions/yasnippet/snippets/erlang-mode/imp b/epy/extensions/yasnippet/snippets/erlang-mode/imp similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/imp rename to epy/extensions/yasnippet/snippets/erlang-mode/imp diff --git a/extensions/yasnippet/snippets/erlang-mode/inc b/epy/extensions/yasnippet/snippets/erlang-mode/inc similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/inc rename to epy/extensions/yasnippet/snippets/erlang-mode/inc diff --git a/extensions/yasnippet/snippets/erlang-mode/inc.lib b/epy/extensions/yasnippet/snippets/erlang-mode/inc.lib similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/inc.lib rename to epy/extensions/yasnippet/snippets/erlang-mode/inc.lib diff --git a/extensions/yasnippet/snippets/erlang-mode/loop b/epy/extensions/yasnippet/snippets/erlang-mode/loop similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/loop rename to epy/extensions/yasnippet/snippets/erlang-mode/loop diff --git a/extensions/yasnippet/snippets/erlang-mode/mod b/epy/extensions/yasnippet/snippets/erlang-mode/mod similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/mod rename to epy/extensions/yasnippet/snippets/erlang-mode/mod diff --git a/extensions/yasnippet/snippets/erlang-mode/rcv b/epy/extensions/yasnippet/snippets/erlang-mode/rcv similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/rcv rename to epy/extensions/yasnippet/snippets/erlang-mode/rcv diff --git a/extensions/yasnippet/snippets/erlang-mode/rcv.after b/epy/extensions/yasnippet/snippets/erlang-mode/rcv.after similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/rcv.after rename to epy/extensions/yasnippet/snippets/erlang-mode/rcv.after diff --git a/extensions/yasnippet/snippets/erlang-mode/rec b/epy/extensions/yasnippet/snippets/erlang-mode/rec similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/rec rename to epy/extensions/yasnippet/snippets/erlang-mode/rec diff --git a/extensions/yasnippet/snippets/erlang-mode/try b/epy/extensions/yasnippet/snippets/erlang-mode/try similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/try rename to epy/extensions/yasnippet/snippets/erlang-mode/try diff --git a/extensions/yasnippet/snippets/erlang-mode/undef b/epy/extensions/yasnippet/snippets/erlang-mode/undef similarity index 100% rename from extensions/yasnippet/snippets/erlang-mode/undef rename to epy/extensions/yasnippet/snippets/erlang-mode/undef diff --git a/extensions/yasnippet/snippets/f90-mode/.yas-parents b/epy/extensions/yasnippet/snippets/f90-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/f90-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/f90-mode/au b/epy/extensions/yasnippet/snippets/f90-mode/au similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/au rename to epy/extensions/yasnippet/snippets/f90-mode/au diff --git a/extensions/yasnippet/snippets/f90-mode/bd b/epy/extensions/yasnippet/snippets/f90-mode/bd similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/bd rename to epy/extensions/yasnippet/snippets/f90-mode/bd diff --git a/extensions/yasnippet/snippets/f90-mode/c b/epy/extensions/yasnippet/snippets/f90-mode/c similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/c rename to epy/extensions/yasnippet/snippets/f90-mode/c diff --git a/extensions/yasnippet/snippets/f90-mode/ch b/epy/extensions/yasnippet/snippets/f90-mode/ch similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/ch rename to epy/extensions/yasnippet/snippets/f90-mode/ch diff --git a/extensions/yasnippet/snippets/f90-mode/cx b/epy/extensions/yasnippet/snippets/f90-mode/cx similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/cx rename to epy/extensions/yasnippet/snippets/f90-mode/cx diff --git a/extensions/yasnippet/snippets/f90-mode/dc b/epy/extensions/yasnippet/snippets/f90-mode/dc similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/dc rename to epy/extensions/yasnippet/snippets/f90-mode/dc diff --git a/extensions/yasnippet/snippets/f90-mode/do b/epy/extensions/yasnippet/snippets/f90-mode/do similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/do rename to epy/extensions/yasnippet/snippets/f90-mode/do diff --git a/extensions/yasnippet/snippets/f90-mode/dp b/epy/extensions/yasnippet/snippets/f90-mode/dp similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/dp rename to epy/extensions/yasnippet/snippets/f90-mode/dp diff --git a/extensions/yasnippet/snippets/f90-mode/eq b/epy/extensions/yasnippet/snippets/f90-mode/eq similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/eq rename to epy/extensions/yasnippet/snippets/f90-mode/eq diff --git a/extensions/yasnippet/snippets/f90-mode/ib b/epy/extensions/yasnippet/snippets/f90-mode/ib similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/ib rename to epy/extensions/yasnippet/snippets/f90-mode/ib diff --git a/extensions/yasnippet/snippets/f90-mode/ic b/epy/extensions/yasnippet/snippets/f90-mode/ic similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/ic rename to epy/extensions/yasnippet/snippets/f90-mode/ic diff --git a/extensions/yasnippet/snippets/f90-mode/ich b/epy/extensions/yasnippet/snippets/f90-mode/ich similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/ich rename to epy/extensions/yasnippet/snippets/f90-mode/ich diff --git a/extensions/yasnippet/snippets/f90-mode/if b/epy/extensions/yasnippet/snippets/f90-mode/if similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/if rename to epy/extensions/yasnippet/snippets/f90-mode/if diff --git a/extensions/yasnippet/snippets/f90-mode/ii b/epy/extensions/yasnippet/snippets/f90-mode/ii similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/ii rename to epy/extensions/yasnippet/snippets/f90-mode/ii diff --git a/extensions/yasnippet/snippets/f90-mode/il b/epy/extensions/yasnippet/snippets/f90-mode/il similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/il rename to epy/extensions/yasnippet/snippets/f90-mode/il diff --git a/extensions/yasnippet/snippets/f90-mode/in b/epy/extensions/yasnippet/snippets/f90-mode/in similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/in rename to epy/extensions/yasnippet/snippets/f90-mode/in diff --git a/extensions/yasnippet/snippets/f90-mode/inc b/epy/extensions/yasnippet/snippets/f90-mode/inc similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/inc rename to epy/extensions/yasnippet/snippets/f90-mode/inc diff --git a/extensions/yasnippet/snippets/f90-mode/intr b/epy/extensions/yasnippet/snippets/f90-mode/intr similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/intr rename to epy/extensions/yasnippet/snippets/f90-mode/intr diff --git a/extensions/yasnippet/snippets/f90-mode/ir b/epy/extensions/yasnippet/snippets/f90-mode/ir similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/ir rename to epy/extensions/yasnippet/snippets/f90-mode/ir diff --git a/extensions/yasnippet/snippets/f90-mode/l b/epy/extensions/yasnippet/snippets/f90-mode/l similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/l rename to epy/extensions/yasnippet/snippets/f90-mode/l diff --git a/extensions/yasnippet/snippets/f90-mode/pa b/epy/extensions/yasnippet/snippets/f90-mode/pa similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/pa rename to epy/extensions/yasnippet/snippets/f90-mode/pa diff --git a/extensions/yasnippet/snippets/f90-mode/pr b/epy/extensions/yasnippet/snippets/f90-mode/pr similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/pr rename to epy/extensions/yasnippet/snippets/f90-mode/pr diff --git a/extensions/yasnippet/snippets/f90-mode/re b/epy/extensions/yasnippet/snippets/f90-mode/re similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/re rename to epy/extensions/yasnippet/snippets/f90-mode/re diff --git a/extensions/yasnippet/snippets/f90-mode/st b/epy/extensions/yasnippet/snippets/f90-mode/st similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/st rename to epy/extensions/yasnippet/snippets/f90-mode/st diff --git a/extensions/yasnippet/snippets/f90-mode/su b/epy/extensions/yasnippet/snippets/f90-mode/su similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/su rename to epy/extensions/yasnippet/snippets/f90-mode/su diff --git a/extensions/yasnippet/snippets/f90-mode/wr b/epy/extensions/yasnippet/snippets/f90-mode/wr similarity index 100% rename from extensions/yasnippet/snippets/f90-mode/wr rename to epy/extensions/yasnippet/snippets/f90-mode/wr diff --git a/extensions/yasnippet/snippets/nxml-mode/.yas-make-groups b/epy/extensions/yasnippet/snippets/html-mode/.yas-make-groups similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/.yas-make-groups rename to epy/extensions/yasnippet/snippets/html-mode/.yas-make-groups diff --git a/extensions/yasnippet/snippets/html-mode/.yas-parents b/epy/extensions/yasnippet/snippets/html-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/html-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/html-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/html-mode/b.yasnippet b/epy/extensions/yasnippet/snippets/html-mode/b.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/html-mode/b.yasnippet rename to epy/extensions/yasnippet/snippets/html-mode/b.yasnippet diff --git a/extensions/yasnippet/snippets/html-mode/body b/epy/extensions/yasnippet/snippets/html-mode/body similarity index 100% rename from extensions/yasnippet/snippets/html-mode/body rename to epy/extensions/yasnippet/snippets/html-mode/body diff --git a/extensions/yasnippet/snippets/html-mode/br b/epy/extensions/yasnippet/snippets/html-mode/br similarity index 100% rename from extensions/yasnippet/snippets/html-mode/br rename to epy/extensions/yasnippet/snippets/html-mode/br diff --git a/extensions/yasnippet/snippets/html-mode/code b/epy/extensions/yasnippet/snippets/html-mode/code similarity index 100% rename from extensions/yasnippet/snippets/html-mode/code rename to epy/extensions/yasnippet/snippets/html-mode/code diff --git a/extensions/yasnippet/snippets/html-mode/code.class b/epy/extensions/yasnippet/snippets/html-mode/code.class similarity index 100% rename from extensions/yasnippet/snippets/html-mode/code.class rename to epy/extensions/yasnippet/snippets/html-mode/code.class diff --git a/extensions/yasnippet/snippets/html-mode/div b/epy/extensions/yasnippet/snippets/html-mode/div similarity index 100% rename from extensions/yasnippet/snippets/html-mode/div rename to epy/extensions/yasnippet/snippets/html-mode/div diff --git a/extensions/yasnippet/snippets/html-mode/div.class b/epy/extensions/yasnippet/snippets/html-mode/div.class similarity index 100% rename from extensions/yasnippet/snippets/html-mode/div.class rename to epy/extensions/yasnippet/snippets/html-mode/div.class diff --git a/extensions/yasnippet/snippets/html-mode/div.id b/epy/extensions/yasnippet/snippets/html-mode/div.id similarity index 100% rename from extensions/yasnippet/snippets/html-mode/div.id rename to epy/extensions/yasnippet/snippets/html-mode/div.id diff --git a/extensions/yasnippet/snippets/html-mode/div.id-class b/epy/extensions/yasnippet/snippets/html-mode/div.id-class similarity index 100% rename from extensions/yasnippet/snippets/html-mode/div.id-class rename to epy/extensions/yasnippet/snippets/html-mode/div.id-class diff --git a/extensions/yasnippet/snippets/html-mode/dov b/epy/extensions/yasnippet/snippets/html-mode/dov similarity index 100% rename from extensions/yasnippet/snippets/html-mode/dov rename to epy/extensions/yasnippet/snippets/html-mode/dov diff --git a/extensions/yasnippet/snippets/html-mode/form b/epy/extensions/yasnippet/snippets/html-mode/form similarity index 100% rename from extensions/yasnippet/snippets/html-mode/form rename to epy/extensions/yasnippet/snippets/html-mode/form diff --git a/extensions/yasnippet/snippets/html-mode/head b/epy/extensions/yasnippet/snippets/html-mode/head similarity index 100% rename from extensions/yasnippet/snippets/html-mode/head rename to epy/extensions/yasnippet/snippets/html-mode/head diff --git a/extensions/yasnippet/snippets/html-mode/header/h1 b/epy/extensions/yasnippet/snippets/html-mode/header/h1 similarity index 100% rename from extensions/yasnippet/snippets/html-mode/header/h1 rename to epy/extensions/yasnippet/snippets/html-mode/header/h1 diff --git a/extensions/yasnippet/snippets/html-mode/header/h2 b/epy/extensions/yasnippet/snippets/html-mode/header/h2 similarity index 100% rename from extensions/yasnippet/snippets/html-mode/header/h2 rename to epy/extensions/yasnippet/snippets/html-mode/header/h2 diff --git a/extensions/yasnippet/snippets/html-mode/header/h3 b/epy/extensions/yasnippet/snippets/html-mode/header/h3 similarity index 100% rename from extensions/yasnippet/snippets/html-mode/header/h3 rename to epy/extensions/yasnippet/snippets/html-mode/header/h3 diff --git a/extensions/yasnippet/snippets/html-mode/header/h4 b/epy/extensions/yasnippet/snippets/html-mode/header/h4 similarity index 100% rename from extensions/yasnippet/snippets/html-mode/header/h4 rename to epy/extensions/yasnippet/snippets/html-mode/header/h4 diff --git a/extensions/yasnippet/snippets/html-mode/header/h5 b/epy/extensions/yasnippet/snippets/html-mode/header/h5 similarity index 100% rename from extensions/yasnippet/snippets/html-mode/header/h5 rename to epy/extensions/yasnippet/snippets/html-mode/header/h5 diff --git a/extensions/yasnippet/snippets/html-mode/header/h6 b/epy/extensions/yasnippet/snippets/html-mode/header/h6 similarity index 100% rename from extensions/yasnippet/snippets/html-mode/header/h6 rename to epy/extensions/yasnippet/snippets/html-mode/header/h6 diff --git a/extensions/yasnippet/snippets/html-mode/hr b/epy/extensions/yasnippet/snippets/html-mode/hr similarity index 100% rename from extensions/yasnippet/snippets/html-mode/hr rename to epy/extensions/yasnippet/snippets/html-mode/hr diff --git a/extensions/yasnippet/snippets/html-mode/href b/epy/extensions/yasnippet/snippets/html-mode/href similarity index 100% rename from extensions/yasnippet/snippets/html-mode/href rename to epy/extensions/yasnippet/snippets/html-mode/href diff --git a/extensions/yasnippet/snippets/html-mode/html b/epy/extensions/yasnippet/snippets/html-mode/html similarity index 100% rename from extensions/yasnippet/snippets/html-mode/html rename to epy/extensions/yasnippet/snippets/html-mode/html diff --git a/extensions/yasnippet/snippets/html-mode/html.xmlns b/epy/extensions/yasnippet/snippets/html-mode/html.xmlns similarity index 100% rename from extensions/yasnippet/snippets/html-mode/html.xmlns rename to epy/extensions/yasnippet/snippets/html-mode/html.xmlns diff --git a/extensions/yasnippet/snippets/html-mode/i.yasnippet b/epy/extensions/yasnippet/snippets/html-mode/i.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/html-mode/i.yasnippet rename to epy/extensions/yasnippet/snippets/html-mode/i.yasnippet diff --git a/extensions/yasnippet/snippets/html-mode/img b/epy/extensions/yasnippet/snippets/html-mode/img similarity index 100% rename from extensions/yasnippet/snippets/html-mode/img rename to epy/extensions/yasnippet/snippets/html-mode/img diff --git a/extensions/yasnippet/snippets/html-mode/input b/epy/extensions/yasnippet/snippets/html-mode/input similarity index 100% rename from extensions/yasnippet/snippets/html-mode/input rename to epy/extensions/yasnippet/snippets/html-mode/input diff --git a/extensions/yasnippet/snippets/html-mode/link.stylesheet b/epy/extensions/yasnippet/snippets/html-mode/link.stylesheet similarity index 100% rename from extensions/yasnippet/snippets/html-mode/link.stylesheet rename to epy/extensions/yasnippet/snippets/html-mode/link.stylesheet diff --git a/extensions/yasnippet/snippets/html-mode/link.stylesheet-ie b/epy/extensions/yasnippet/snippets/html-mode/link.stylesheet-ie similarity index 100% rename from extensions/yasnippet/snippets/html-mode/link.stylesheet-ie rename to epy/extensions/yasnippet/snippets/html-mode/link.stylesheet-ie diff --git a/extensions/yasnippet/snippets/html-mode/list/dd b/epy/extensions/yasnippet/snippets/html-mode/list/dd similarity index 100% rename from extensions/yasnippet/snippets/html-mode/list/dd rename to epy/extensions/yasnippet/snippets/html-mode/list/dd diff --git a/extensions/yasnippet/snippets/html-mode/list/dl b/epy/extensions/yasnippet/snippets/html-mode/list/dl similarity index 100% rename from extensions/yasnippet/snippets/html-mode/list/dl rename to epy/extensions/yasnippet/snippets/html-mode/list/dl diff --git a/extensions/yasnippet/snippets/html-mode/list/dl.id b/epy/extensions/yasnippet/snippets/html-mode/list/dl.id similarity index 100% rename from extensions/yasnippet/snippets/html-mode/list/dl.id rename to epy/extensions/yasnippet/snippets/html-mode/list/dl.id diff --git a/extensions/yasnippet/snippets/html-mode/list/dt b/epy/extensions/yasnippet/snippets/html-mode/list/dt similarity index 100% rename from extensions/yasnippet/snippets/html-mode/list/dt rename to epy/extensions/yasnippet/snippets/html-mode/list/dt diff --git a/extensions/yasnippet/snippets/html-mode/list/li b/epy/extensions/yasnippet/snippets/html-mode/list/li similarity index 100% rename from extensions/yasnippet/snippets/html-mode/list/li rename to epy/extensions/yasnippet/snippets/html-mode/list/li diff --git a/extensions/yasnippet/snippets/html-mode/list/li.class b/epy/extensions/yasnippet/snippets/html-mode/list/li.class similarity index 100% rename from extensions/yasnippet/snippets/html-mode/list/li.class rename to epy/extensions/yasnippet/snippets/html-mode/list/li.class diff --git a/extensions/yasnippet/snippets/html-mode/list/ol b/epy/extensions/yasnippet/snippets/html-mode/list/ol similarity index 100% rename from extensions/yasnippet/snippets/html-mode/list/ol rename to epy/extensions/yasnippet/snippets/html-mode/list/ol diff --git a/extensions/yasnippet/snippets/html-mode/list/ol.class b/epy/extensions/yasnippet/snippets/html-mode/list/ol.class similarity index 100% rename from extensions/yasnippet/snippets/html-mode/list/ol.class rename to epy/extensions/yasnippet/snippets/html-mode/list/ol.class diff --git a/extensions/yasnippet/snippets/html-mode/list/ol.id b/epy/extensions/yasnippet/snippets/html-mode/list/ol.id similarity index 100% rename from extensions/yasnippet/snippets/html-mode/list/ol.id rename to epy/extensions/yasnippet/snippets/html-mode/list/ol.id diff --git a/extensions/yasnippet/snippets/html-mode/list/ul b/epy/extensions/yasnippet/snippets/html-mode/list/ul similarity index 100% rename from extensions/yasnippet/snippets/html-mode/list/ul rename to epy/extensions/yasnippet/snippets/html-mode/list/ul diff --git a/extensions/yasnippet/snippets/html-mode/list/ul.class b/epy/extensions/yasnippet/snippets/html-mode/list/ul.class similarity index 100% rename from extensions/yasnippet/snippets/html-mode/list/ul.class rename to epy/extensions/yasnippet/snippets/html-mode/list/ul.class diff --git a/extensions/yasnippet/snippets/html-mode/list/ul.id b/epy/extensions/yasnippet/snippets/html-mode/list/ul.id similarity index 100% rename from extensions/yasnippet/snippets/html-mode/list/ul.id rename to epy/extensions/yasnippet/snippets/html-mode/list/ul.id diff --git a/extensions/yasnippet/snippets/html-mode/mailto b/epy/extensions/yasnippet/snippets/html-mode/mailto similarity index 100% rename from extensions/yasnippet/snippets/html-mode/mailto rename to epy/extensions/yasnippet/snippets/html-mode/mailto diff --git a/extensions/yasnippet/snippets/html-mode/meta/doctype b/epy/extensions/yasnippet/snippets/html-mode/meta/doctype similarity index 100% rename from extensions/yasnippet/snippets/html-mode/meta/doctype rename to epy/extensions/yasnippet/snippets/html-mode/meta/doctype diff --git a/extensions/yasnippet/snippets/html-mode/meta/doctype.xhml1 b/epy/extensions/yasnippet/snippets/html-mode/meta/doctype.xhml1 similarity index 100% rename from extensions/yasnippet/snippets/html-mode/meta/doctype.xhml1 rename to epy/extensions/yasnippet/snippets/html-mode/meta/doctype.xhml1 diff --git a/extensions/yasnippet/snippets/html-mode/meta/doctype.xhtml1_1 b/epy/extensions/yasnippet/snippets/html-mode/meta/doctype.xhtml1_1 similarity index 100% rename from extensions/yasnippet/snippets/html-mode/meta/doctype.xhtml1_1 rename to epy/extensions/yasnippet/snippets/html-mode/meta/doctype.xhtml1_1 diff --git a/extensions/yasnippet/snippets/html-mode/meta/doctype.xhtml1_strict b/epy/extensions/yasnippet/snippets/html-mode/meta/doctype.xhtml1_strict similarity index 100% rename from extensions/yasnippet/snippets/html-mode/meta/doctype.xhtml1_strict rename to epy/extensions/yasnippet/snippets/html-mode/meta/doctype.xhtml1_strict diff --git a/extensions/yasnippet/snippets/html-mode/meta/doctype.xhtml1_transitional b/epy/extensions/yasnippet/snippets/html-mode/meta/doctype.xhtml1_transitional similarity index 100% rename from extensions/yasnippet/snippets/html-mode/meta/doctype.xhtml1_transitional rename to epy/extensions/yasnippet/snippets/html-mode/meta/doctype.xhtml1_transitional diff --git a/extensions/yasnippet/snippets/html-mode/meta/meta b/epy/extensions/yasnippet/snippets/html-mode/meta/meta similarity index 100% rename from extensions/yasnippet/snippets/html-mode/meta/meta rename to epy/extensions/yasnippet/snippets/html-mode/meta/meta diff --git a/extensions/yasnippet/snippets/html-mode/meta/meta.http-equiv b/epy/extensions/yasnippet/snippets/html-mode/meta/meta.http-equiv similarity index 100% rename from extensions/yasnippet/snippets/html-mode/meta/meta.http-equiv rename to epy/extensions/yasnippet/snippets/html-mode/meta/meta.http-equiv diff --git a/extensions/yasnippet/snippets/html-mode/p b/epy/extensions/yasnippet/snippets/html-mode/p similarity index 100% rename from extensions/yasnippet/snippets/html-mode/p rename to epy/extensions/yasnippet/snippets/html-mode/p diff --git a/extensions/yasnippet/snippets/html-mode/pre b/epy/extensions/yasnippet/snippets/html-mode/pre similarity index 100% rename from extensions/yasnippet/snippets/html-mode/pre rename to epy/extensions/yasnippet/snippets/html-mode/pre diff --git a/extensions/yasnippet/snippets/html-mode/q.yasnippet b/epy/extensions/yasnippet/snippets/html-mode/q.yasnippet similarity index 100% rename from extensions/yasnippet/snippets/html-mode/q.yasnippet rename to epy/extensions/yasnippet/snippets/html-mode/q.yasnippet diff --git a/extensions/yasnippet/snippets/html-mode/quote b/epy/extensions/yasnippet/snippets/html-mode/quote similarity index 100% rename from extensions/yasnippet/snippets/html-mode/quote rename to epy/extensions/yasnippet/snippets/html-mode/quote diff --git a/extensions/yasnippet/snippets/html-mode/script.javascript b/epy/extensions/yasnippet/snippets/html-mode/script.javascript similarity index 100% rename from extensions/yasnippet/snippets/html-mode/script.javascript rename to epy/extensions/yasnippet/snippets/html-mode/script.javascript diff --git a/extensions/yasnippet/snippets/html-mode/script.javascript-src b/epy/extensions/yasnippet/snippets/html-mode/script.javascript-src similarity index 100% rename from extensions/yasnippet/snippets/html-mode/script.javascript-src rename to epy/extensions/yasnippet/snippets/html-mode/script.javascript-src diff --git a/extensions/yasnippet/snippets/html-mode/span b/epy/extensions/yasnippet/snippets/html-mode/span similarity index 100% rename from extensions/yasnippet/snippets/html-mode/span rename to epy/extensions/yasnippet/snippets/html-mode/span diff --git a/extensions/yasnippet/snippets/html-mode/span.class b/epy/extensions/yasnippet/snippets/html-mode/span.class similarity index 100% rename from extensions/yasnippet/snippets/html-mode/span.class rename to epy/extensions/yasnippet/snippets/html-mode/span.class diff --git a/extensions/yasnippet/snippets/html-mode/span.id b/epy/extensions/yasnippet/snippets/html-mode/span.id similarity index 100% rename from extensions/yasnippet/snippets/html-mode/span.id rename to epy/extensions/yasnippet/snippets/html-mode/span.id diff --git a/extensions/yasnippet/snippets/html-mode/style b/epy/extensions/yasnippet/snippets/html-mode/style similarity index 100% rename from extensions/yasnippet/snippets/html-mode/style rename to epy/extensions/yasnippet/snippets/html-mode/style diff --git a/extensions/yasnippet/snippets/html-mode/table/table b/epy/extensions/yasnippet/snippets/html-mode/table/table similarity index 100% rename from extensions/yasnippet/snippets/html-mode/table/table rename to epy/extensions/yasnippet/snippets/html-mode/table/table diff --git a/extensions/yasnippet/snippets/html-mode/table/td b/epy/extensions/yasnippet/snippets/html-mode/table/td similarity index 100% rename from extensions/yasnippet/snippets/html-mode/table/td rename to epy/extensions/yasnippet/snippets/html-mode/table/td diff --git a/extensions/yasnippet/snippets/html-mode/table/th b/epy/extensions/yasnippet/snippets/html-mode/table/th similarity index 100% rename from extensions/yasnippet/snippets/html-mode/table/th rename to epy/extensions/yasnippet/snippets/html-mode/table/th diff --git a/extensions/yasnippet/snippets/html-mode/table/tr b/epy/extensions/yasnippet/snippets/html-mode/table/tr similarity index 100% rename from extensions/yasnippet/snippets/html-mode/table/tr rename to epy/extensions/yasnippet/snippets/html-mode/table/tr diff --git a/extensions/yasnippet/snippets/html-mode/textarea b/epy/extensions/yasnippet/snippets/html-mode/textarea similarity index 100% rename from extensions/yasnippet/snippets/html-mode/textarea rename to epy/extensions/yasnippet/snippets/html-mode/textarea diff --git a/extensions/yasnippet/snippets/html-mode/title b/epy/extensions/yasnippet/snippets/html-mode/title similarity index 100% rename from extensions/yasnippet/snippets/html-mode/title rename to epy/extensions/yasnippet/snippets/html-mode/title diff --git a/extensions/yasnippet/snippets/latex-mode/.yas-parents b/epy/extensions/yasnippet/snippets/latex-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/latex-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/latex-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/latex-mode/begin b/epy/extensions/yasnippet/snippets/latex-mode/begin similarity index 100% rename from extensions/yasnippet/snippets/latex-mode/begin rename to epy/extensions/yasnippet/snippets/latex-mode/begin diff --git a/extensions/yasnippet/snippets/markdown-mode/+ b/epy/extensions/yasnippet/snippets/markdown-mode/+ similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/+ rename to epy/extensions/yasnippet/snippets/markdown-mode/+ diff --git a/extensions/yasnippet/snippets/markdown-mode/- b/epy/extensions/yasnippet/snippets/markdown-mode/- similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/- rename to epy/extensions/yasnippet/snippets/markdown-mode/- diff --git a/extensions/yasnippet/snippets/markdown-mode/.yas-parents b/epy/extensions/yasnippet/snippets/markdown-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/markdown-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/markdown-mode/_ b/epy/extensions/yasnippet/snippets/markdown-mode/_ similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/_ rename to epy/extensions/yasnippet/snippets/markdown-mode/_ diff --git a/extensions/yasnippet/snippets/markdown-mode/__ b/epy/extensions/yasnippet/snippets/markdown-mode/__ similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/__ rename to epy/extensions/yasnippet/snippets/markdown-mode/__ diff --git a/extensions/yasnippet/snippets/markdown-mode/` b/epy/extensions/yasnippet/snippets/markdown-mode/` similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/` rename to epy/extensions/yasnippet/snippets/markdown-mode/` diff --git a/extensions/yasnippet/snippets/markdown-mode/h1.1 b/epy/extensions/yasnippet/snippets/markdown-mode/h1.1 similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/h1.1 rename to epy/extensions/yasnippet/snippets/markdown-mode/h1.1 diff --git a/extensions/yasnippet/snippets/markdown-mode/h1.2 b/epy/extensions/yasnippet/snippets/markdown-mode/h1.2 similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/h1.2 rename to epy/extensions/yasnippet/snippets/markdown-mode/h1.2 diff --git a/extensions/yasnippet/snippets/markdown-mode/h2.1 b/epy/extensions/yasnippet/snippets/markdown-mode/h2.1 similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/h2.1 rename to epy/extensions/yasnippet/snippets/markdown-mode/h2.1 diff --git a/extensions/yasnippet/snippets/markdown-mode/h2.2 b/epy/extensions/yasnippet/snippets/markdown-mode/h2.2 similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/h2.2 rename to epy/extensions/yasnippet/snippets/markdown-mode/h2.2 diff --git a/extensions/yasnippet/snippets/markdown-mode/h3 b/epy/extensions/yasnippet/snippets/markdown-mode/h3 similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/h3 rename to epy/extensions/yasnippet/snippets/markdown-mode/h3 diff --git a/extensions/yasnippet/snippets/markdown-mode/h4 b/epy/extensions/yasnippet/snippets/markdown-mode/h4 similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/h4 rename to epy/extensions/yasnippet/snippets/markdown-mode/h4 diff --git a/extensions/yasnippet/snippets/markdown-mode/h5 b/epy/extensions/yasnippet/snippets/markdown-mode/h5 similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/h5 rename to epy/extensions/yasnippet/snippets/markdown-mode/h5 diff --git a/extensions/yasnippet/snippets/markdown-mode/h6 b/epy/extensions/yasnippet/snippets/markdown-mode/h6 similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/h6 rename to epy/extensions/yasnippet/snippets/markdown-mode/h6 diff --git a/extensions/yasnippet/snippets/markdown-mode/hr.1 b/epy/extensions/yasnippet/snippets/markdown-mode/hr.1 similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/hr.1 rename to epy/extensions/yasnippet/snippets/markdown-mode/hr.1 diff --git a/extensions/yasnippet/snippets/markdown-mode/hr.2 b/epy/extensions/yasnippet/snippets/markdown-mode/hr.2 similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/hr.2 rename to epy/extensions/yasnippet/snippets/markdown-mode/hr.2 diff --git a/extensions/yasnippet/snippets/markdown-mode/img b/epy/extensions/yasnippet/snippets/markdown-mode/img similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/img rename to epy/extensions/yasnippet/snippets/markdown-mode/img diff --git a/extensions/yasnippet/snippets/markdown-mode/link b/epy/extensions/yasnippet/snippets/markdown-mode/link similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/link rename to epy/extensions/yasnippet/snippets/markdown-mode/link diff --git a/extensions/yasnippet/snippets/markdown-mode/ol b/epy/extensions/yasnippet/snippets/markdown-mode/ol similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/ol rename to epy/extensions/yasnippet/snippets/markdown-mode/ol diff --git a/extensions/yasnippet/snippets/markdown-mode/rimg b/epy/extensions/yasnippet/snippets/markdown-mode/rimg similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/rimg rename to epy/extensions/yasnippet/snippets/markdown-mode/rimg diff --git a/extensions/yasnippet/snippets/markdown-mode/rlb b/epy/extensions/yasnippet/snippets/markdown-mode/rlb similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/rlb rename to epy/extensions/yasnippet/snippets/markdown-mode/rlb diff --git a/extensions/yasnippet/snippets/markdown-mode/rlink b/epy/extensions/yasnippet/snippets/markdown-mode/rlink similarity index 100% rename from extensions/yasnippet/snippets/markdown-mode/rlink rename to epy/extensions/yasnippet/snippets/markdown-mode/rlink diff --git a/extensions/yasnippet/snippets/ruby-mode/.yas-make-groups b/epy/extensions/yasnippet/snippets/nxml-mode/.yas-make-groups similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/.yas-make-groups rename to epy/extensions/yasnippet/snippets/nxml-mode/.yas-make-groups diff --git a/extensions/yasnippet/snippets/nxml-mode/.yas-parents b/epy/extensions/yasnippet/snippets/nxml-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/nxml-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/nxml-mode/body b/epy/extensions/yasnippet/snippets/nxml-mode/body similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/body rename to epy/extensions/yasnippet/snippets/nxml-mode/body diff --git a/extensions/yasnippet/snippets/nxml-mode/br b/epy/extensions/yasnippet/snippets/nxml-mode/br similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/br rename to epy/extensions/yasnippet/snippets/nxml-mode/br diff --git a/extensions/yasnippet/snippets/nxml-mode/code b/epy/extensions/yasnippet/snippets/nxml-mode/code similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/code rename to epy/extensions/yasnippet/snippets/nxml-mode/code diff --git a/extensions/yasnippet/snippets/nxml-mode/div b/epy/extensions/yasnippet/snippets/nxml-mode/div similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/div rename to epy/extensions/yasnippet/snippets/nxml-mode/div diff --git a/extensions/yasnippet/snippets/nxml-mode/form b/epy/extensions/yasnippet/snippets/nxml-mode/form similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/form rename to epy/extensions/yasnippet/snippets/nxml-mode/form diff --git a/extensions/yasnippet/snippets/nxml-mode/head b/epy/extensions/yasnippet/snippets/nxml-mode/head similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/head rename to epy/extensions/yasnippet/snippets/nxml-mode/head diff --git a/extensions/yasnippet/snippets/nxml-mode/header/h1 b/epy/extensions/yasnippet/snippets/nxml-mode/header/h1 similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/header/h1 rename to epy/extensions/yasnippet/snippets/nxml-mode/header/h1 diff --git a/extensions/yasnippet/snippets/nxml-mode/header/h2 b/epy/extensions/yasnippet/snippets/nxml-mode/header/h2 similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/header/h2 rename to epy/extensions/yasnippet/snippets/nxml-mode/header/h2 diff --git a/extensions/yasnippet/snippets/nxml-mode/header/h3 b/epy/extensions/yasnippet/snippets/nxml-mode/header/h3 similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/header/h3 rename to epy/extensions/yasnippet/snippets/nxml-mode/header/h3 diff --git a/extensions/yasnippet/snippets/nxml-mode/header/h4 b/epy/extensions/yasnippet/snippets/nxml-mode/header/h4 similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/header/h4 rename to epy/extensions/yasnippet/snippets/nxml-mode/header/h4 diff --git a/extensions/yasnippet/snippets/nxml-mode/header/h5 b/epy/extensions/yasnippet/snippets/nxml-mode/header/h5 similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/header/h5 rename to epy/extensions/yasnippet/snippets/nxml-mode/header/h5 diff --git a/extensions/yasnippet/snippets/nxml-mode/header/h6 b/epy/extensions/yasnippet/snippets/nxml-mode/header/h6 similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/header/h6 rename to epy/extensions/yasnippet/snippets/nxml-mode/header/h6 diff --git a/extensions/yasnippet/snippets/nxml-mode/hr b/epy/extensions/yasnippet/snippets/nxml-mode/hr similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/hr rename to epy/extensions/yasnippet/snippets/nxml-mode/hr diff --git a/extensions/yasnippet/snippets/nxml-mode/href b/epy/extensions/yasnippet/snippets/nxml-mode/href similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/href rename to epy/extensions/yasnippet/snippets/nxml-mode/href diff --git a/extensions/yasnippet/snippets/nxml-mode/html b/epy/extensions/yasnippet/snippets/nxml-mode/html similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/html rename to epy/extensions/yasnippet/snippets/nxml-mode/html diff --git a/extensions/yasnippet/snippets/nxml-mode/img b/epy/extensions/yasnippet/snippets/nxml-mode/img similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/img rename to epy/extensions/yasnippet/snippets/nxml-mode/img diff --git a/extensions/yasnippet/snippets/nxml-mode/input b/epy/extensions/yasnippet/snippets/nxml-mode/input similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/input rename to epy/extensions/yasnippet/snippets/nxml-mode/input diff --git a/extensions/yasnippet/snippets/nxml-mode/li b/epy/extensions/yasnippet/snippets/nxml-mode/li similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/li rename to epy/extensions/yasnippet/snippets/nxml-mode/li diff --git a/extensions/yasnippet/snippets/nxml-mode/link b/epy/extensions/yasnippet/snippets/nxml-mode/link similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/link rename to epy/extensions/yasnippet/snippets/nxml-mode/link diff --git a/extensions/yasnippet/snippets/nxml-mode/meta/doctype b/epy/extensions/yasnippet/snippets/nxml-mode/meta/doctype similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/meta/doctype rename to epy/extensions/yasnippet/snippets/nxml-mode/meta/doctype diff --git a/extensions/yasnippet/snippets/nxml-mode/meta/doctype.xhtml1_strict b/epy/extensions/yasnippet/snippets/nxml-mode/meta/doctype.xhtml1_strict similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/meta/doctype.xhtml1_strict rename to epy/extensions/yasnippet/snippets/nxml-mode/meta/doctype.xhtml1_strict diff --git a/extensions/yasnippet/snippets/nxml-mode/meta/doctype.xhtml1_transitional b/epy/extensions/yasnippet/snippets/nxml-mode/meta/doctype.xhtml1_transitional similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/meta/doctype.xhtml1_transitional rename to epy/extensions/yasnippet/snippets/nxml-mode/meta/doctype.xhtml1_transitional diff --git a/extensions/yasnippet/snippets/nxml-mode/meta/meta b/epy/extensions/yasnippet/snippets/nxml-mode/meta/meta similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/meta/meta rename to epy/extensions/yasnippet/snippets/nxml-mode/meta/meta diff --git a/extensions/yasnippet/snippets/nxml-mode/name b/epy/extensions/yasnippet/snippets/nxml-mode/name similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/name rename to epy/extensions/yasnippet/snippets/nxml-mode/name diff --git a/extensions/yasnippet/snippets/nxml-mode/ol b/epy/extensions/yasnippet/snippets/nxml-mode/ol similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/ol rename to epy/extensions/yasnippet/snippets/nxml-mode/ol diff --git a/extensions/yasnippet/snippets/nxml-mode/p b/epy/extensions/yasnippet/snippets/nxml-mode/p similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/p rename to epy/extensions/yasnippet/snippets/nxml-mode/p diff --git a/extensions/yasnippet/snippets/nxml-mode/pre b/epy/extensions/yasnippet/snippets/nxml-mode/pre similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/pre rename to epy/extensions/yasnippet/snippets/nxml-mode/pre diff --git a/extensions/yasnippet/snippets/nxml-mode/quote b/epy/extensions/yasnippet/snippets/nxml-mode/quote similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/quote rename to epy/extensions/yasnippet/snippets/nxml-mode/quote diff --git a/extensions/yasnippet/snippets/nxml-mode/span b/epy/extensions/yasnippet/snippets/nxml-mode/span similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/span rename to epy/extensions/yasnippet/snippets/nxml-mode/span diff --git a/extensions/yasnippet/snippets/nxml-mode/style b/epy/extensions/yasnippet/snippets/nxml-mode/style similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/style rename to epy/extensions/yasnippet/snippets/nxml-mode/style diff --git a/extensions/yasnippet/snippets/nxml-mode/table b/epy/extensions/yasnippet/snippets/nxml-mode/table similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/table rename to epy/extensions/yasnippet/snippets/nxml-mode/table diff --git a/extensions/yasnippet/snippets/nxml-mode/tag.1l b/epy/extensions/yasnippet/snippets/nxml-mode/tag.1l similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/tag.1l rename to epy/extensions/yasnippet/snippets/nxml-mode/tag.1l diff --git a/extensions/yasnippet/snippets/nxml-mode/tag.2l b/epy/extensions/yasnippet/snippets/nxml-mode/tag.2l similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/tag.2l rename to epy/extensions/yasnippet/snippets/nxml-mode/tag.2l diff --git a/extensions/yasnippet/snippets/nxml-mode/td b/epy/extensions/yasnippet/snippets/nxml-mode/td similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/td rename to epy/extensions/yasnippet/snippets/nxml-mode/td diff --git a/extensions/yasnippet/snippets/nxml-mode/th b/epy/extensions/yasnippet/snippets/nxml-mode/th similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/th rename to epy/extensions/yasnippet/snippets/nxml-mode/th diff --git a/extensions/yasnippet/snippets/nxml-mode/title b/epy/extensions/yasnippet/snippets/nxml-mode/title similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/title rename to epy/extensions/yasnippet/snippets/nxml-mode/title diff --git a/extensions/yasnippet/snippets/nxml-mode/tr b/epy/extensions/yasnippet/snippets/nxml-mode/tr similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/tr rename to epy/extensions/yasnippet/snippets/nxml-mode/tr diff --git a/extensions/yasnippet/snippets/nxml-mode/ul b/epy/extensions/yasnippet/snippets/nxml-mode/ul similarity index 100% rename from extensions/yasnippet/snippets/nxml-mode/ul rename to epy/extensions/yasnippet/snippets/nxml-mode/ul diff --git a/extensions/yasnippet/snippets/objc-mode/.yas-parents b/epy/extensions/yasnippet/snippets/objc-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/objc-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/objc-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/objc-mode/prop b/epy/extensions/yasnippet/snippets/objc-mode/prop similarity index 100% rename from extensions/yasnippet/snippets/objc-mode/prop rename to epy/extensions/yasnippet/snippets/objc-mode/prop diff --git a/extensions/yasnippet/snippets/perl-mode/.yas-parents b/epy/extensions/yasnippet/snippets/perl-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/perl-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/perl-mode/eval b/epy/extensions/yasnippet/snippets/perl-mode/eval similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/eval rename to epy/extensions/yasnippet/snippets/perl-mode/eval diff --git a/extensions/yasnippet/snippets/perl-mode/for b/epy/extensions/yasnippet/snippets/perl-mode/for similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/for rename to epy/extensions/yasnippet/snippets/perl-mode/for diff --git a/extensions/yasnippet/snippets/perl-mode/fore b/epy/extensions/yasnippet/snippets/perl-mode/fore similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/fore rename to epy/extensions/yasnippet/snippets/perl-mode/fore diff --git a/extensions/yasnippet/snippets/perl-mode/if b/epy/extensions/yasnippet/snippets/perl-mode/if similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/if rename to epy/extensions/yasnippet/snippets/perl-mode/if diff --git a/extensions/yasnippet/snippets/perl-mode/ife b/epy/extensions/yasnippet/snippets/perl-mode/ife similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/ife rename to epy/extensions/yasnippet/snippets/perl-mode/ife diff --git a/extensions/yasnippet/snippets/perl-mode/ifee b/epy/extensions/yasnippet/snippets/perl-mode/ifee similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/ifee rename to epy/extensions/yasnippet/snippets/perl-mode/ifee diff --git a/extensions/yasnippet/snippets/perl-mode/sub b/epy/extensions/yasnippet/snippets/perl-mode/sub similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/sub rename to epy/extensions/yasnippet/snippets/perl-mode/sub diff --git a/extensions/yasnippet/snippets/perl-mode/unless b/epy/extensions/yasnippet/snippets/perl-mode/unless similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/unless rename to epy/extensions/yasnippet/snippets/perl-mode/unless diff --git a/extensions/yasnippet/snippets/perl-mode/while b/epy/extensions/yasnippet/snippets/perl-mode/while similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/while rename to epy/extensions/yasnippet/snippets/perl-mode/while diff --git a/extensions/yasnippet/snippets/perl-mode/xfore b/epy/extensions/yasnippet/snippets/perl-mode/xfore similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/xfore rename to epy/extensions/yasnippet/snippets/perl-mode/xfore diff --git a/extensions/yasnippet/snippets/perl-mode/xif b/epy/extensions/yasnippet/snippets/perl-mode/xif similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/xif rename to epy/extensions/yasnippet/snippets/perl-mode/xif diff --git a/extensions/yasnippet/snippets/perl-mode/xunless b/epy/extensions/yasnippet/snippets/perl-mode/xunless similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/xunless rename to epy/extensions/yasnippet/snippets/perl-mode/xunless diff --git a/extensions/yasnippet/snippets/perl-mode/xwhile b/epy/extensions/yasnippet/snippets/perl-mode/xwhile similarity index 100% rename from extensions/yasnippet/snippets/perl-mode/xwhile rename to epy/extensions/yasnippet/snippets/perl-mode/xwhile diff --git a/extensions/yasnippet/snippets/python-mode/.yas-parents b/epy/extensions/yasnippet/snippets/python-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/python-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/python-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/python-mode/__ b/epy/extensions/yasnippet/snippets/python-mode/__ similarity index 100% rename from extensions/yasnippet/snippets/python-mode/__ rename to epy/extensions/yasnippet/snippets/python-mode/__ diff --git a/extensions/yasnippet/snippets/python-mode/class b/epy/extensions/yasnippet/snippets/python-mode/class similarity index 100% rename from extensions/yasnippet/snippets/python-mode/class rename to epy/extensions/yasnippet/snippets/python-mode/class diff --git a/extensions/yasnippet/snippets/python-mode/def b/epy/extensions/yasnippet/snippets/python-mode/def similarity index 100% rename from extensions/yasnippet/snippets/python-mode/def rename to epy/extensions/yasnippet/snippets/python-mode/def diff --git a/extensions/yasnippet/snippets/python-mode/defm b/epy/extensions/yasnippet/snippets/python-mode/defm similarity index 100% rename from extensions/yasnippet/snippets/python-mode/defm rename to epy/extensions/yasnippet/snippets/python-mode/defm diff --git a/extensions/yasnippet/snippets/python-mode/doc b/epy/extensions/yasnippet/snippets/python-mode/doc similarity index 100% rename from extensions/yasnippet/snippets/python-mode/doc rename to epy/extensions/yasnippet/snippets/python-mode/doc diff --git a/extensions/yasnippet/snippets/python-mode/for b/epy/extensions/yasnippet/snippets/python-mode/for similarity index 100% rename from extensions/yasnippet/snippets/python-mode/for rename to epy/extensions/yasnippet/snippets/python-mode/for diff --git a/extensions/yasnippet/snippets/python-mode/from b/epy/extensions/yasnippet/snippets/python-mode/from similarity index 100% rename from extensions/yasnippet/snippets/python-mode/from rename to epy/extensions/yasnippet/snippets/python-mode/from diff --git a/extensions/yasnippet/snippets/python-mode/ifmain b/epy/extensions/yasnippet/snippets/python-mode/ifmain similarity index 100% rename from extensions/yasnippet/snippets/python-mode/ifmain rename to epy/extensions/yasnippet/snippets/python-mode/ifmain diff --git a/extensions/yasnippet/snippets/python-mode/init b/epy/extensions/yasnippet/snippets/python-mode/init similarity index 100% rename from extensions/yasnippet/snippets/python-mode/init rename to epy/extensions/yasnippet/snippets/python-mode/init diff --git a/extensions/yasnippet/snippets/python-mode/ipdb b/epy/extensions/yasnippet/snippets/python-mode/ipdb similarity index 100% rename from extensions/yasnippet/snippets/python-mode/ipdb rename to epy/extensions/yasnippet/snippets/python-mode/ipdb diff --git a/extensions/yasnippet/snippets/python-mode/param b/epy/extensions/yasnippet/snippets/python-mode/param similarity index 100% rename from extensions/yasnippet/snippets/python-mode/param rename to epy/extensions/yasnippet/snippets/python-mode/param diff --git a/extensions/yasnippet/snippets/python-mode/pdb b/epy/extensions/yasnippet/snippets/python-mode/pdb similarity index 100% rename from extensions/yasnippet/snippets/python-mode/pdb rename to epy/extensions/yasnippet/snippets/python-mode/pdb diff --git a/extensions/yasnippet/snippets/python-mode/prop b/epy/extensions/yasnippet/snippets/python-mode/prop similarity index 100% rename from extensions/yasnippet/snippets/python-mode/prop rename to epy/extensions/yasnippet/snippets/python-mode/prop diff --git a/extensions/yasnippet/snippets/python-mode/prop.fun b/epy/extensions/yasnippet/snippets/python-mode/prop.fun similarity index 100% rename from extensions/yasnippet/snippets/python-mode/prop.fun rename to epy/extensions/yasnippet/snippets/python-mode/prop.fun diff --git a/extensions/yasnippet/snippets/python-mode/propg b/epy/extensions/yasnippet/snippets/python-mode/propg similarity index 100% rename from extensions/yasnippet/snippets/python-mode/propg rename to epy/extensions/yasnippet/snippets/python-mode/propg diff --git a/extensions/yasnippet/snippets/python-mode/propsg b/epy/extensions/yasnippet/snippets/python-mode/propsg similarity index 100% rename from extensions/yasnippet/snippets/python-mode/propsg rename to epy/extensions/yasnippet/snippets/python-mode/propsg diff --git a/extensions/yasnippet/snippets/python-mode/super b/epy/extensions/yasnippet/snippets/python-mode/super similarity index 100% rename from extensions/yasnippet/snippets/python-mode/super rename to epy/extensions/yasnippet/snippets/python-mode/super diff --git a/extensions/yasnippet/snippets/python-mode/testcase b/epy/extensions/yasnippet/snippets/python-mode/testcase similarity index 100% rename from extensions/yasnippet/snippets/python-mode/testcase rename to epy/extensions/yasnippet/snippets/python-mode/testcase diff --git a/extensions/yasnippet/snippets/python-mode/try.except b/epy/extensions/yasnippet/snippets/python-mode/try.except similarity index 100% rename from extensions/yasnippet/snippets/python-mode/try.except rename to epy/extensions/yasnippet/snippets/python-mode/try.except diff --git a/extensions/yasnippet/snippets/python-mode/try.exceptelse b/epy/extensions/yasnippet/snippets/python-mode/try.exceptelse similarity index 100% rename from extensions/yasnippet/snippets/python-mode/try.exceptelse rename to epy/extensions/yasnippet/snippets/python-mode/try.exceptelse diff --git a/extensions/yasnippet/snippets/python-mode/try.exceptelsefinally b/epy/extensions/yasnippet/snippets/python-mode/try.exceptelsefinally similarity index 100% rename from extensions/yasnippet/snippets/python-mode/try.exceptelsefinally rename to epy/extensions/yasnippet/snippets/python-mode/try.exceptelsefinally diff --git a/extensions/yasnippet/snippets/python-mode/try.exceptfinally b/epy/extensions/yasnippet/snippets/python-mode/try.exceptfinally similarity index 100% rename from extensions/yasnippet/snippets/python-mode/try.exceptfinally rename to epy/extensions/yasnippet/snippets/python-mode/try.exceptfinally diff --git a/extensions/yasnippet/snippets/python-mode/utf8 b/epy/extensions/yasnippet/snippets/python-mode/utf8 similarity index 100% rename from extensions/yasnippet/snippets/python-mode/utf8 rename to epy/extensions/yasnippet/snippets/python-mode/utf8 diff --git a/extensions/yasnippet/snippets/python-mode/while b/epy/extensions/yasnippet/snippets/python-mode/while similarity index 100% rename from extensions/yasnippet/snippets/python-mode/while rename to epy/extensions/yasnippet/snippets/python-mode/while diff --git a/extensions/yasnippet/snippets/rst-mode/.yas-parents b/epy/extensions/yasnippet/snippets/rst-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/rst-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/rst-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/rst-mode/chap b/epy/extensions/yasnippet/snippets/rst-mode/chap similarity index 100% rename from extensions/yasnippet/snippets/rst-mode/chap rename to epy/extensions/yasnippet/snippets/rst-mode/chap diff --git a/extensions/yasnippet/snippets/rst-mode/sec b/epy/extensions/yasnippet/snippets/rst-mode/sec similarity index 100% rename from extensions/yasnippet/snippets/rst-mode/sec rename to epy/extensions/yasnippet/snippets/rst-mode/sec diff --git a/extensions/yasnippet/snippets/rst-mode/tit b/epy/extensions/yasnippet/snippets/rst-mode/tit similarity index 100% rename from extensions/yasnippet/snippets/rst-mode/tit rename to epy/extensions/yasnippet/snippets/rst-mode/tit diff --git a/epy/extensions/yasnippet/snippets/ruby-mode/.yas-make-groups b/epy/extensions/yasnippet/snippets/ruby-mode/.yas-make-groups new file mode 100644 index 0000000..e69de29 diff --git a/extensions/yasnippet/snippets/ruby-mode/.yas-parents b/epy/extensions/yasnippet/snippets/ruby-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/ruby-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/all b/epy/extensions/yasnippet/snippets/ruby-mode/collections/all similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/all rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/all diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/any b/epy/extensions/yasnippet/snippets/ruby-mode/collections/any similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/any rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/any diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/classify b/epy/extensions/yasnippet/snippets/ruby-mode/collections/classify similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/classify rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/classify diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/collect b/epy/extensions/yasnippet/snippets/ruby-mode/collections/collect similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/collect rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/collect diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/deli b/epy/extensions/yasnippet/snippets/ruby-mode/collections/deli similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/deli rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/deli diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/det b/epy/extensions/yasnippet/snippets/ruby-mode/collections/det similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/det rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/det diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/ea b/epy/extensions/yasnippet/snippets/ruby-mode/collections/ea similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/ea rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/ea diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/eac b/epy/extensions/yasnippet/snippets/ruby-mode/collections/eac similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/eac rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/eac diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/eai b/epy/extensions/yasnippet/snippets/ruby-mode/collections/eai similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/eai rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/eai diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/eav b/epy/extensions/yasnippet/snippets/ruby-mode/collections/eav similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/eav rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/eav diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/eawi b/epy/extensions/yasnippet/snippets/ruby-mode/collections/eawi similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/eawi rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/eawi diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/inject b/epy/extensions/yasnippet/snippets/ruby-mode/collections/inject similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/inject rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/inject diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/reject b/epy/extensions/yasnippet/snippets/ruby-mode/collections/reject similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/reject rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/reject diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/select b/epy/extensions/yasnippet/snippets/ruby-mode/collections/select similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/select rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/select diff --git a/extensions/yasnippet/snippets/ruby-mode/collections/zip b/epy/extensions/yasnippet/snippets/ruby-mode/collections/zip similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/collections/zip rename to epy/extensions/yasnippet/snippets/ruby-mode/collections/zip diff --git a/extensions/yasnippet/snippets/ruby-mode/control structure/forin b/epy/extensions/yasnippet/snippets/ruby-mode/control structure/forin similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/control structure/forin rename to epy/extensions/yasnippet/snippets/ruby-mode/control structure/forin diff --git a/extensions/yasnippet/snippets/ruby-mode/control structure/if b/epy/extensions/yasnippet/snippets/ruby-mode/control structure/if similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/control structure/if rename to epy/extensions/yasnippet/snippets/ruby-mode/control structure/if diff --git a/extensions/yasnippet/snippets/ruby-mode/control structure/ife b/epy/extensions/yasnippet/snippets/ruby-mode/control structure/ife similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/control structure/ife rename to epy/extensions/yasnippet/snippets/ruby-mode/control structure/ife diff --git a/extensions/yasnippet/snippets/ruby-mode/control structure/tim b/epy/extensions/yasnippet/snippets/ruby-mode/control structure/tim similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/control structure/tim rename to epy/extensions/yasnippet/snippets/ruby-mode/control structure/tim diff --git a/extensions/yasnippet/snippets/ruby-mode/control structure/until b/epy/extensions/yasnippet/snippets/ruby-mode/control structure/until similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/control structure/until rename to epy/extensions/yasnippet/snippets/ruby-mode/control structure/until diff --git a/extensions/yasnippet/snippets/ruby-mode/control structure/upt b/epy/extensions/yasnippet/snippets/ruby-mode/control structure/upt similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/control structure/upt rename to epy/extensions/yasnippet/snippets/ruby-mode/control structure/upt diff --git a/extensions/yasnippet/snippets/ruby-mode/control structure/when b/epy/extensions/yasnippet/snippets/ruby-mode/control structure/when similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/control structure/when rename to epy/extensions/yasnippet/snippets/ruby-mode/control structure/when diff --git a/extensions/yasnippet/snippets/ruby-mode/control structure/while b/epy/extensions/yasnippet/snippets/ruby-mode/control structure/while similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/control structure/while rename to epy/extensions/yasnippet/snippets/ruby-mode/control structure/while diff --git a/extensions/yasnippet/snippets/ruby-mode/definitions/Comp b/epy/extensions/yasnippet/snippets/ruby-mode/definitions/Comp similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/definitions/Comp rename to epy/extensions/yasnippet/snippets/ruby-mode/definitions/Comp diff --git a/extensions/yasnippet/snippets/ruby-mode/definitions/am b/epy/extensions/yasnippet/snippets/ruby-mode/definitions/am similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/definitions/am rename to epy/extensions/yasnippet/snippets/ruby-mode/definitions/am diff --git a/extensions/yasnippet/snippets/ruby-mode/definitions/cla b/epy/extensions/yasnippet/snippets/ruby-mode/definitions/cla similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/definitions/cla rename to epy/extensions/yasnippet/snippets/ruby-mode/definitions/cla diff --git a/extensions/yasnippet/snippets/ruby-mode/definitions/cls b/epy/extensions/yasnippet/snippets/ruby-mode/definitions/cls similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/definitions/cls rename to epy/extensions/yasnippet/snippets/ruby-mode/definitions/cls diff --git a/extensions/yasnippet/snippets/ruby-mode/definitions/mm b/epy/extensions/yasnippet/snippets/ruby-mode/definitions/mm similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/definitions/mm rename to epy/extensions/yasnippet/snippets/ruby-mode/definitions/mm diff --git a/extensions/yasnippet/snippets/ruby-mode/definitions/r b/epy/extensions/yasnippet/snippets/ruby-mode/definitions/r similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/definitions/r rename to epy/extensions/yasnippet/snippets/ruby-mode/definitions/r diff --git a/extensions/yasnippet/snippets/ruby-mode/definitions/rw b/epy/extensions/yasnippet/snippets/ruby-mode/definitions/rw similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/definitions/rw rename to epy/extensions/yasnippet/snippets/ruby-mode/definitions/rw diff --git a/extensions/yasnippet/snippets/ruby-mode/definitions/w b/epy/extensions/yasnippet/snippets/ruby-mode/definitions/w similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/definitions/w rename to epy/extensions/yasnippet/snippets/ruby-mode/definitions/w diff --git a/extensions/yasnippet/snippets/ruby-mode/general/# b/epy/extensions/yasnippet/snippets/ruby-mode/general/# similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/general/# rename to epy/extensions/yasnippet/snippets/ruby-mode/general/# diff --git a/extensions/yasnippet/snippets/ruby-mode/general/=b b/epy/extensions/yasnippet/snippets/ruby-mode/general/=b similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/general/=b rename to epy/extensions/yasnippet/snippets/ruby-mode/general/=b diff --git a/extensions/yasnippet/snippets/ruby-mode/general/app b/epy/extensions/yasnippet/snippets/ruby-mode/general/app similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/general/app rename to epy/extensions/yasnippet/snippets/ruby-mode/general/app diff --git a/extensions/yasnippet/snippets/ruby-mode/general/bm b/epy/extensions/yasnippet/snippets/ruby-mode/general/bm similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/general/bm rename to epy/extensions/yasnippet/snippets/ruby-mode/general/bm diff --git a/extensions/yasnippet/snippets/ruby-mode/general/case b/epy/extensions/yasnippet/snippets/ruby-mode/general/case similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/general/case rename to epy/extensions/yasnippet/snippets/ruby-mode/general/case diff --git a/extensions/yasnippet/snippets/ruby-mode/general/dee b/epy/extensions/yasnippet/snippets/ruby-mode/general/dee similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/general/dee rename to epy/extensions/yasnippet/snippets/ruby-mode/general/dee diff --git a/extensions/yasnippet/snippets/ruby-mode/general/rb b/epy/extensions/yasnippet/snippets/ruby-mode/general/rb similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/general/rb rename to epy/extensions/yasnippet/snippets/ruby-mode/general/rb diff --git a/extensions/yasnippet/snippets/ruby-mode/general/req b/epy/extensions/yasnippet/snippets/ruby-mode/general/req similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/general/req rename to epy/extensions/yasnippet/snippets/ruby-mode/general/req diff --git a/extensions/yasnippet/snippets/ruby-mode/general/rreq b/epy/extensions/yasnippet/snippets/ruby-mode/general/rreq similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/general/rreq rename to epy/extensions/yasnippet/snippets/ruby-mode/general/rreq diff --git a/extensions/yasnippet/snippets/ruby-mode/general/y b/epy/extensions/yasnippet/snippets/ruby-mode/general/y similarity index 100% rename from extensions/yasnippet/snippets/ruby-mode/general/y rename to epy/extensions/yasnippet/snippets/ruby-mode/general/y diff --git a/extensions/yasnippet/snippets/scala-mode/.yas-parents b/epy/extensions/yasnippet/snippets/scala-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/scala-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/scala-mode/act b/epy/extensions/yasnippet/snippets/scala-mode/act similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/act rename to epy/extensions/yasnippet/snippets/scala-mode/act diff --git a/extensions/yasnippet/snippets/scala-mode/act.arg b/epy/extensions/yasnippet/snippets/scala-mode/act.arg similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/act.arg rename to epy/extensions/yasnippet/snippets/scala-mode/act.arg diff --git a/extensions/yasnippet/snippets/scala-mode/actor b/epy/extensions/yasnippet/snippets/scala-mode/actor similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/actor rename to epy/extensions/yasnippet/snippets/scala-mode/actor diff --git a/extensions/yasnippet/snippets/scala-mode/ano b/epy/extensions/yasnippet/snippets/scala-mode/ano similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/ano rename to epy/extensions/yasnippet/snippets/scala-mode/ano diff --git a/extensions/yasnippet/snippets/scala-mode/app b/epy/extensions/yasnippet/snippets/scala-mode/app similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/app rename to epy/extensions/yasnippet/snippets/scala-mode/app diff --git a/extensions/yasnippet/snippets/scala-mode/arr.new b/epy/extensions/yasnippet/snippets/scala-mode/arr.new similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/arr.new rename to epy/extensions/yasnippet/snippets/scala-mode/arr.new diff --git a/extensions/yasnippet/snippets/scala-mode/arr.val-new b/epy/extensions/yasnippet/snippets/scala-mode/arr.val-new similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/arr.val-new rename to epy/extensions/yasnippet/snippets/scala-mode/arr.val-new diff --git a/extensions/yasnippet/snippets/scala-mode/asof b/epy/extensions/yasnippet/snippets/scala-mode/asof similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/asof rename to epy/extensions/yasnippet/snippets/scala-mode/asof diff --git a/extensions/yasnippet/snippets/scala-mode/ass b/epy/extensions/yasnippet/snippets/scala-mode/ass similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/ass rename to epy/extensions/yasnippet/snippets/scala-mode/ass diff --git a/extensions/yasnippet/snippets/scala-mode/ass.true b/epy/extensions/yasnippet/snippets/scala-mode/ass.true similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/ass.true rename to epy/extensions/yasnippet/snippets/scala-mode/ass.true diff --git a/extensions/yasnippet/snippets/scala-mode/at.author b/epy/extensions/yasnippet/snippets/scala-mode/at.author similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/at.author rename to epy/extensions/yasnippet/snippets/scala-mode/at.author diff --git a/extensions/yasnippet/snippets/scala-mode/at.param b/epy/extensions/yasnippet/snippets/scala-mode/at.param similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/at.param rename to epy/extensions/yasnippet/snippets/scala-mode/at.param diff --git a/extensions/yasnippet/snippets/scala-mode/at.return b/epy/extensions/yasnippet/snippets/scala-mode/at.return similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/at.return rename to epy/extensions/yasnippet/snippets/scala-mode/at.return diff --git a/extensions/yasnippet/snippets/scala-mode/at.version b/epy/extensions/yasnippet/snippets/scala-mode/at.version similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/at.version rename to epy/extensions/yasnippet/snippets/scala-mode/at.version diff --git a/extensions/yasnippet/snippets/scala-mode/bang b/epy/extensions/yasnippet/snippets/scala-mode/bang similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/bang rename to epy/extensions/yasnippet/snippets/scala-mode/bang diff --git a/extensions/yasnippet/snippets/scala-mode/case b/epy/extensions/yasnippet/snippets/scala-mode/case similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/case rename to epy/extensions/yasnippet/snippets/scala-mode/case diff --git a/extensions/yasnippet/snippets/scala-mode/case.match-all b/epy/extensions/yasnippet/snippets/scala-mode/case.match-all similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/case.match-all rename to epy/extensions/yasnippet/snippets/scala-mode/case.match-all diff --git a/extensions/yasnippet/snippets/scala-mode/cast b/epy/extensions/yasnippet/snippets/scala-mode/cast similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/cast rename to epy/extensions/yasnippet/snippets/scala-mode/cast diff --git a/extensions/yasnippet/snippets/scala-mode/cc b/epy/extensions/yasnippet/snippets/scala-mode/cc similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/cc rename to epy/extensions/yasnippet/snippets/scala-mode/cc diff --git a/extensions/yasnippet/snippets/scala-mode/cl b/epy/extensions/yasnippet/snippets/scala-mode/cl similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/cl rename to epy/extensions/yasnippet/snippets/scala-mode/cl diff --git a/extensions/yasnippet/snippets/scala-mode/cl.abs b/epy/extensions/yasnippet/snippets/scala-mode/cl.abs similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/cl.abs rename to epy/extensions/yasnippet/snippets/scala-mode/cl.abs diff --git a/extensions/yasnippet/snippets/scala-mode/cl.abs-arg b/epy/extensions/yasnippet/snippets/scala-mode/cl.abs-arg similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/cl.abs-arg rename to epy/extensions/yasnippet/snippets/scala-mode/cl.abs-arg diff --git a/extensions/yasnippet/snippets/scala-mode/cl.arg b/epy/extensions/yasnippet/snippets/scala-mode/cl.arg similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/cl.arg rename to epy/extensions/yasnippet/snippets/scala-mode/cl.arg diff --git a/extensions/yasnippet/snippets/scala-mode/clof b/epy/extensions/yasnippet/snippets/scala-mode/clof similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/clof rename to epy/extensions/yasnippet/snippets/scala-mode/clof diff --git a/extensions/yasnippet/snippets/scala-mode/co b/epy/extensions/yasnippet/snippets/scala-mode/co similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/co rename to epy/extensions/yasnippet/snippets/scala-mode/co diff --git a/extensions/yasnippet/snippets/scala-mode/cons b/epy/extensions/yasnippet/snippets/scala-mode/cons similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/cons rename to epy/extensions/yasnippet/snippets/scala-mode/cons diff --git a/extensions/yasnippet/snippets/scala-mode/cons.nil b/epy/extensions/yasnippet/snippets/scala-mode/cons.nil similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/cons.nil rename to epy/extensions/yasnippet/snippets/scala-mode/cons.nil diff --git a/extensions/yasnippet/snippets/scala-mode/def.arg b/epy/extensions/yasnippet/snippets/scala-mode/def.arg similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/def.arg rename to epy/extensions/yasnippet/snippets/scala-mode/def.arg diff --git a/extensions/yasnippet/snippets/scala-mode/def.arg-body b/epy/extensions/yasnippet/snippets/scala-mode/def.arg-body similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/def.arg-body rename to epy/extensions/yasnippet/snippets/scala-mode/def.arg-body diff --git a/extensions/yasnippet/snippets/scala-mode/def.arg-ret b/epy/extensions/yasnippet/snippets/scala-mode/def.arg-ret similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/def.arg-ret rename to epy/extensions/yasnippet/snippets/scala-mode/def.arg-ret diff --git a/extensions/yasnippet/snippets/scala-mode/def.arg-ret-body b/epy/extensions/yasnippet/snippets/scala-mode/def.arg-ret-body similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/def.arg-ret-body rename to epy/extensions/yasnippet/snippets/scala-mode/def.arg-ret-body diff --git a/extensions/yasnippet/snippets/scala-mode/def.body b/epy/extensions/yasnippet/snippets/scala-mode/def.body similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/def.body rename to epy/extensions/yasnippet/snippets/scala-mode/def.body diff --git a/extensions/yasnippet/snippets/scala-mode/def.ret b/epy/extensions/yasnippet/snippets/scala-mode/def.ret similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/def.ret rename to epy/extensions/yasnippet/snippets/scala-mode/def.ret diff --git a/extensions/yasnippet/snippets/scala-mode/def.ret-body b/epy/extensions/yasnippet/snippets/scala-mode/def.ret-body similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/def.ret-body rename to epy/extensions/yasnippet/snippets/scala-mode/def.ret-body diff --git a/extensions/yasnippet/snippets/scala-mode/def.simple b/epy/extensions/yasnippet/snippets/scala-mode/def.simple similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/def.simple rename to epy/extensions/yasnippet/snippets/scala-mode/def.simple diff --git a/extensions/yasnippet/snippets/scala-mode/doc.class b/epy/extensions/yasnippet/snippets/scala-mode/doc.class similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/doc.class rename to epy/extensions/yasnippet/snippets/scala-mode/doc.class diff --git a/extensions/yasnippet/snippets/scala-mode/doc.def b/epy/extensions/yasnippet/snippets/scala-mode/doc.def similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/doc.def rename to epy/extensions/yasnippet/snippets/scala-mode/doc.def diff --git a/extensions/yasnippet/snippets/scala-mode/doc.file b/epy/extensions/yasnippet/snippets/scala-mode/doc.file similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/doc.file rename to epy/extensions/yasnippet/snippets/scala-mode/doc.file diff --git a/extensions/yasnippet/snippets/scala-mode/doc.file-scala b/epy/extensions/yasnippet/snippets/scala-mode/doc.file-scala similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/doc.file-scala rename to epy/extensions/yasnippet/snippets/scala-mode/doc.file-scala diff --git a/extensions/yasnippet/snippets/scala-mode/doc.file-scala-api b/epy/extensions/yasnippet/snippets/scala-mode/doc.file-scala-api similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/doc.file-scala-api rename to epy/extensions/yasnippet/snippets/scala-mode/doc.file-scala-api diff --git a/extensions/yasnippet/snippets/scala-mode/doc.scaladoc b/epy/extensions/yasnippet/snippets/scala-mode/doc.scaladoc similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/doc.scaladoc rename to epy/extensions/yasnippet/snippets/scala-mode/doc.scaladoc diff --git a/extensions/yasnippet/snippets/scala-mode/expect b/epy/extensions/yasnippet/snippets/scala-mode/expect similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/expect rename to epy/extensions/yasnippet/snippets/scala-mode/expect diff --git a/extensions/yasnippet/snippets/scala-mode/ext b/epy/extensions/yasnippet/snippets/scala-mode/ext similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/ext rename to epy/extensions/yasnippet/snippets/scala-mode/ext diff --git a/extensions/yasnippet/snippets/scala-mode/for.extract b/epy/extensions/yasnippet/snippets/scala-mode/for.extract similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/for.extract rename to epy/extensions/yasnippet/snippets/scala-mode/for.extract diff --git a/extensions/yasnippet/snippets/scala-mode/for.if b/epy/extensions/yasnippet/snippets/scala-mode/for.if similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/for.if rename to epy/extensions/yasnippet/snippets/scala-mode/for.if diff --git a/extensions/yasnippet/snippets/scala-mode/for.loop b/epy/extensions/yasnippet/snippets/scala-mode/for.loop similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/for.loop rename to epy/extensions/yasnippet/snippets/scala-mode/for.loop diff --git a/extensions/yasnippet/snippets/scala-mode/for.multi b/epy/extensions/yasnippet/snippets/scala-mode/for.multi similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/for.multi rename to epy/extensions/yasnippet/snippets/scala-mode/for.multi diff --git a/extensions/yasnippet/snippets/scala-mode/foreach b/epy/extensions/yasnippet/snippets/scala-mode/foreach similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/foreach rename to epy/extensions/yasnippet/snippets/scala-mode/foreach diff --git a/extensions/yasnippet/snippets/scala-mode/hmap.new b/epy/extensions/yasnippet/snippets/scala-mode/hmap.new similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/hmap.new rename to epy/extensions/yasnippet/snippets/scala-mode/hmap.new diff --git a/extensions/yasnippet/snippets/scala-mode/hmap.val-new b/epy/extensions/yasnippet/snippets/scala-mode/hmap.val-new similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/hmap.val-new rename to epy/extensions/yasnippet/snippets/scala-mode/hmap.val-new diff --git a/extensions/yasnippet/snippets/scala-mode/hset.new b/epy/extensions/yasnippet/snippets/scala-mode/hset.new similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/hset.new rename to epy/extensions/yasnippet/snippets/scala-mode/hset.new diff --git a/extensions/yasnippet/snippets/scala-mode/hset.val-new b/epy/extensions/yasnippet/snippets/scala-mode/hset.val-new similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/hset.val-new rename to epy/extensions/yasnippet/snippets/scala-mode/hset.val-new diff --git a/extensions/yasnippet/snippets/scala-mode/if b/epy/extensions/yasnippet/snippets/scala-mode/if similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/if rename to epy/extensions/yasnippet/snippets/scala-mode/if diff --git a/extensions/yasnippet/snippets/scala-mode/if.else b/epy/extensions/yasnippet/snippets/scala-mode/if.else similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/if.else rename to epy/extensions/yasnippet/snippets/scala-mode/if.else diff --git a/extensions/yasnippet/snippets/scala-mode/imp b/epy/extensions/yasnippet/snippets/scala-mode/imp similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/imp rename to epy/extensions/yasnippet/snippets/scala-mode/imp diff --git a/extensions/yasnippet/snippets/scala-mode/intercept b/epy/extensions/yasnippet/snippets/scala-mode/intercept similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/intercept rename to epy/extensions/yasnippet/snippets/scala-mode/intercept diff --git a/extensions/yasnippet/snippets/scala-mode/isof b/epy/extensions/yasnippet/snippets/scala-mode/isof similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/isof rename to epy/extensions/yasnippet/snippets/scala-mode/isof diff --git a/extensions/yasnippet/snippets/scala-mode/ls.new b/epy/extensions/yasnippet/snippets/scala-mode/ls.new similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/ls.new rename to epy/extensions/yasnippet/snippets/scala-mode/ls.new diff --git a/extensions/yasnippet/snippets/scala-mode/ls.val-new b/epy/extensions/yasnippet/snippets/scala-mode/ls.val-new similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/ls.val-new rename to epy/extensions/yasnippet/snippets/scala-mode/ls.val-new diff --git a/extensions/yasnippet/snippets/scala-mode/main b/epy/extensions/yasnippet/snippets/scala-mode/main similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/main rename to epy/extensions/yasnippet/snippets/scala-mode/main diff --git a/extensions/yasnippet/snippets/scala-mode/map b/epy/extensions/yasnippet/snippets/scala-mode/map similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/map rename to epy/extensions/yasnippet/snippets/scala-mode/map diff --git a/extensions/yasnippet/snippets/scala-mode/map.new b/epy/extensions/yasnippet/snippets/scala-mode/map.new similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/map.new rename to epy/extensions/yasnippet/snippets/scala-mode/map.new diff --git a/extensions/yasnippet/snippets/scala-mode/match b/epy/extensions/yasnippet/snippets/scala-mode/match similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/match rename to epy/extensions/yasnippet/snippets/scala-mode/match diff --git a/extensions/yasnippet/snippets/scala-mode/match.can b/epy/extensions/yasnippet/snippets/scala-mode/match.can similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/match.can rename to epy/extensions/yasnippet/snippets/scala-mode/match.can diff --git a/extensions/yasnippet/snippets/scala-mode/match.option b/epy/extensions/yasnippet/snippets/scala-mode/match.option similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/match.option rename to epy/extensions/yasnippet/snippets/scala-mode/match.option diff --git a/extensions/yasnippet/snippets/scala-mode/mix b/epy/extensions/yasnippet/snippets/scala-mode/mix similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/mix rename to epy/extensions/yasnippet/snippets/scala-mode/mix diff --git a/extensions/yasnippet/snippets/scala-mode/ob b/epy/extensions/yasnippet/snippets/scala-mode/ob similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/ob rename to epy/extensions/yasnippet/snippets/scala-mode/ob diff --git a/extensions/yasnippet/snippets/scala-mode/pac b/epy/extensions/yasnippet/snippets/scala-mode/pac similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/pac rename to epy/extensions/yasnippet/snippets/scala-mode/pac diff --git a/extensions/yasnippet/snippets/scala-mode/pr.newline b/epy/extensions/yasnippet/snippets/scala-mode/pr.newline similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/pr.newline rename to epy/extensions/yasnippet/snippets/scala-mode/pr.newline diff --git a/extensions/yasnippet/snippets/scala-mode/pr.simple b/epy/extensions/yasnippet/snippets/scala-mode/pr.simple similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/pr.simple rename to epy/extensions/yasnippet/snippets/scala-mode/pr.simple diff --git a/extensions/yasnippet/snippets/scala-mode/pr.string b/epy/extensions/yasnippet/snippets/scala-mode/pr.string similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/pr.string rename to epy/extensions/yasnippet/snippets/scala-mode/pr.string diff --git a/extensions/yasnippet/snippets/scala-mode/pr.trace b/epy/extensions/yasnippet/snippets/scala-mode/pr.trace similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/pr.trace rename to epy/extensions/yasnippet/snippets/scala-mode/pr.trace diff --git a/extensions/yasnippet/snippets/scala-mode/pri b/epy/extensions/yasnippet/snippets/scala-mode/pri similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/pri rename to epy/extensions/yasnippet/snippets/scala-mode/pri diff --git a/extensions/yasnippet/snippets/scala-mode/pri.param b/epy/extensions/yasnippet/snippets/scala-mode/pri.param similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/pri.param rename to epy/extensions/yasnippet/snippets/scala-mode/pri.param diff --git a/extensions/yasnippet/snippets/scala-mode/pro b/epy/extensions/yasnippet/snippets/scala-mode/pro similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/pro rename to epy/extensions/yasnippet/snippets/scala-mode/pro diff --git a/extensions/yasnippet/snippets/scala-mode/pro.param b/epy/extensions/yasnippet/snippets/scala-mode/pro.param similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/pro.param rename to epy/extensions/yasnippet/snippets/scala-mode/pro.param diff --git a/extensions/yasnippet/snippets/scala-mode/suite b/epy/extensions/yasnippet/snippets/scala-mode/suite similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/suite rename to epy/extensions/yasnippet/snippets/scala-mode/suite diff --git a/extensions/yasnippet/snippets/scala-mode/test b/epy/extensions/yasnippet/snippets/scala-mode/test similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/test rename to epy/extensions/yasnippet/snippets/scala-mode/test diff --git a/extensions/yasnippet/snippets/scala-mode/throw b/epy/extensions/yasnippet/snippets/scala-mode/throw similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/throw rename to epy/extensions/yasnippet/snippets/scala-mode/throw diff --git a/extensions/yasnippet/snippets/scala-mode/tr b/epy/extensions/yasnippet/snippets/scala-mode/tr similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/tr rename to epy/extensions/yasnippet/snippets/scala-mode/tr diff --git a/extensions/yasnippet/snippets/scala-mode/tr.ext b/epy/extensions/yasnippet/snippets/scala-mode/tr.ext similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/tr.ext rename to epy/extensions/yasnippet/snippets/scala-mode/tr.ext diff --git a/extensions/yasnippet/snippets/scala-mode/tr.ext-with b/epy/extensions/yasnippet/snippets/scala-mode/tr.ext-with similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/tr.ext-with rename to epy/extensions/yasnippet/snippets/scala-mode/tr.ext-with diff --git a/extensions/yasnippet/snippets/scala-mode/tr.with b/epy/extensions/yasnippet/snippets/scala-mode/tr.with similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/tr.with rename to epy/extensions/yasnippet/snippets/scala-mode/tr.with diff --git a/extensions/yasnippet/snippets/scala-mode/try b/epy/extensions/yasnippet/snippets/scala-mode/try similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/try rename to epy/extensions/yasnippet/snippets/scala-mode/try diff --git a/extensions/yasnippet/snippets/scala-mode/try.catch-finally b/epy/extensions/yasnippet/snippets/scala-mode/try.catch-finally similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/try.catch-finally rename to epy/extensions/yasnippet/snippets/scala-mode/try.catch-finally diff --git a/extensions/yasnippet/snippets/scala-mode/try.finally b/epy/extensions/yasnippet/snippets/scala-mode/try.finally similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/try.finally rename to epy/extensions/yasnippet/snippets/scala-mode/try.finally diff --git a/extensions/yasnippet/snippets/scala-mode/tup.arrow b/epy/extensions/yasnippet/snippets/scala-mode/tup.arrow similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/tup.arrow rename to epy/extensions/yasnippet/snippets/scala-mode/tup.arrow diff --git a/extensions/yasnippet/snippets/scala-mode/tup.paren b/epy/extensions/yasnippet/snippets/scala-mode/tup.paren similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/tup.paren rename to epy/extensions/yasnippet/snippets/scala-mode/tup.paren diff --git a/extensions/yasnippet/snippets/scala-mode/val b/epy/extensions/yasnippet/snippets/scala-mode/val similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/val rename to epy/extensions/yasnippet/snippets/scala-mode/val diff --git a/extensions/yasnippet/snippets/scala-mode/val.new b/epy/extensions/yasnippet/snippets/scala-mode/val.new similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/val.new rename to epy/extensions/yasnippet/snippets/scala-mode/val.new diff --git a/extensions/yasnippet/snippets/scala-mode/val.ret b/epy/extensions/yasnippet/snippets/scala-mode/val.ret similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/val.ret rename to epy/extensions/yasnippet/snippets/scala-mode/val.ret diff --git a/extensions/yasnippet/snippets/scala-mode/var b/epy/extensions/yasnippet/snippets/scala-mode/var similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/var rename to epy/extensions/yasnippet/snippets/scala-mode/var diff --git a/extensions/yasnippet/snippets/scala-mode/var.new b/epy/extensions/yasnippet/snippets/scala-mode/var.new similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/var.new rename to epy/extensions/yasnippet/snippets/scala-mode/var.new diff --git a/extensions/yasnippet/snippets/scala-mode/var.ret b/epy/extensions/yasnippet/snippets/scala-mode/var.ret similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/var.ret rename to epy/extensions/yasnippet/snippets/scala-mode/var.ret diff --git a/extensions/yasnippet/snippets/scala-mode/whi b/epy/extensions/yasnippet/snippets/scala-mode/whi similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/whi rename to epy/extensions/yasnippet/snippets/scala-mode/whi diff --git a/extensions/yasnippet/snippets/scala-mode/with b/epy/extensions/yasnippet/snippets/scala-mode/with similarity index 100% rename from extensions/yasnippet/snippets/scala-mode/with rename to epy/extensions/yasnippet/snippets/scala-mode/with diff --git a/extensions/yasnippet/snippets/snippet-mode/.yas-parents b/epy/extensions/yasnippet/snippets/snippet-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/snippet-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/snippet-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/snippet-mode/field b/epy/extensions/yasnippet/snippets/snippet-mode/field similarity index 100% rename from extensions/yasnippet/snippets/snippet-mode/field rename to epy/extensions/yasnippet/snippets/snippet-mode/field diff --git a/extensions/yasnippet/snippets/snippet-mode/mirror b/epy/extensions/yasnippet/snippets/snippet-mode/mirror similarity index 100% rename from extensions/yasnippet/snippets/snippet-mode/mirror rename to epy/extensions/yasnippet/snippets/snippet-mode/mirror diff --git a/extensions/yasnippet/snippets/snippet-mode/vars b/epy/extensions/yasnippet/snippets/snippet-mode/vars similarity index 100% rename from extensions/yasnippet/snippets/snippet-mode/vars rename to epy/extensions/yasnippet/snippets/snippet-mode/vars diff --git a/extensions/yasnippet/snippets/sql-mode/.yas-parents b/epy/extensions/yasnippet/snippets/sql-mode/.yas-parents similarity index 100% rename from extensions/yasnippet/snippets/sql-mode/.yas-parents rename to epy/extensions/yasnippet/snippets/sql-mode/.yas-parents diff --git a/extensions/yasnippet/snippets/sql-mode/column b/epy/extensions/yasnippet/snippets/sql-mode/column similarity index 100% rename from extensions/yasnippet/snippets/sql-mode/column rename to epy/extensions/yasnippet/snippets/sql-mode/column diff --git a/extensions/yasnippet/snippets/sql-mode/constraint b/epy/extensions/yasnippet/snippets/sql-mode/constraint similarity index 100% rename from extensions/yasnippet/snippets/sql-mode/constraint rename to epy/extensions/yasnippet/snippets/sql-mode/constraint diff --git a/extensions/yasnippet/snippets/sql-mode/constraint.1 b/epy/extensions/yasnippet/snippets/sql-mode/constraint.1 similarity index 100% rename from extensions/yasnippet/snippets/sql-mode/constraint.1 rename to epy/extensions/yasnippet/snippets/sql-mode/constraint.1 diff --git a/extensions/yasnippet/snippets/sql-mode/create b/epy/extensions/yasnippet/snippets/sql-mode/create similarity index 100% rename from extensions/yasnippet/snippets/sql-mode/create rename to epy/extensions/yasnippet/snippets/sql-mode/create diff --git a/extensions/yasnippet/snippets/sql-mode/create.1 b/epy/extensions/yasnippet/snippets/sql-mode/create.1 similarity index 100% rename from extensions/yasnippet/snippets/sql-mode/create.1 rename to epy/extensions/yasnippet/snippets/sql-mode/create.1 diff --git a/extensions/yasnippet/snippets/sql-mode/references b/epy/extensions/yasnippet/snippets/sql-mode/references similarity index 100% rename from extensions/yasnippet/snippets/sql-mode/references rename to epy/extensions/yasnippet/snippets/sql-mode/references diff --git a/extensions/yasnippet/snippets/text-mode/email b/epy/extensions/yasnippet/snippets/text-mode/email similarity index 100% rename from extensions/yasnippet/snippets/text-mode/email rename to epy/extensions/yasnippet/snippets/text-mode/email diff --git a/extensions/yasnippet/snippets/text-mode/time b/epy/extensions/yasnippet/snippets/text-mode/time similarity index 100% rename from extensions/yasnippet/snippets/text-mode/time rename to epy/extensions/yasnippet/snippets/text-mode/time diff --git a/extensions/yasnippet/yasnippet-debug.el b/epy/extensions/yasnippet/yasnippet-debug.el similarity index 100% rename from extensions/yasnippet/yasnippet-debug.el rename to epy/extensions/yasnippet/yasnippet-debug.el diff --git a/extensions/yasnippet/yasnippet.el b/epy/extensions/yasnippet/yasnippet.el similarity index 100% rename from extensions/yasnippet/yasnippet.el rename to epy/extensions/yasnippet/yasnippet.el diff --git a/epy/python-libs/.#a.py b/epy/python-libs/.#a.py new file mode 120000 index 0000000..d09433e --- /dev/null +++ b/epy/python-libs/.#a.py @@ -0,0 +1 @@ +eugeneai@inca.irnok.net.2177:1393892527 \ No newline at end of file diff --git a/epy/python-libs/Pymacs-0.25-py2.7.egg b/epy/python-libs/Pymacs-0.25-py2.7.egg new file mode 100644 index 0000000..b9ba0f0 Binary files /dev/null and b/epy/python-libs/Pymacs-0.25-py2.7.egg differ diff --git a/epy/python-libs/easy-install.pth b/epy/python-libs/easy-install.pth new file mode 100644 index 0000000..673a8bc --- /dev/null +++ b/epy/python-libs/easy-install.pth @@ -0,0 +1,6 @@ +import sys; sys.__plen = len(sys.path) +./rope-0.9.4-py2.7.egg +./ropemacs-0.7-py2.7.egg +./ropemode-0.2-py2.7.egg +./Pymacs-0.25-py2.7.egg +import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; p=getattr(sys,'__egginsert',0); sys.path[p:p]=new; sys.__egginsert = p+len(new) diff --git a/python-libs/epy-unittest.py b/epy/python-libs/epy-unittest.py similarity index 100% rename from python-libs/epy-unittest.py rename to epy/python-libs/epy-unittest.py diff --git a/epy/python-libs/install_pymacs.sh b/epy/python-libs/install_pymacs.sh new file mode 100755 index 0000000..e799422 --- /dev/null +++ b/epy/python-libs/install_pymacs.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +#PYMACS_VERSION=0.25 +PYTHON_VERSION=2.7 + +PYTHON=python$PYTHON_VERSION +EI=easy_install-$PYTHON_VERSION + +#cleanup +rm -rf Pymacs* rope* site.* easy-install* + +PYTHONPATH=./ $EI -z -d ./ rope ropemacs +wget https://github.com/pinard/Pymacs/archive/master.tar.gz -O - | tar xzvf - + +DNAME=$(ls -d *Pymacs*) +echo "Pymacs source directory: $DNAME" +cd $DNAME +$PYTHON pppp -C ppppconfig.py *.in contrib tests +$PYTHON setup.py sdist +PYMACS_VERSION=$( python -c "import Pymacs;print(Pymacs.version)" ) +echo "Pymacs-version: $PYMACS_VERSION" +cp dist/Pymacs-$PYMACS_VERSION.tar.gz ../ +cp -i pymacs.el ../../extensions/ +cd .. +rm -rf $DNAME +PYTHONPATH=./ $EI -z -d ./ Pymacs-$PYMACS_VERSION.tar.gz +rm -f Pymacs-$PYMACS_VERSION.tar.gz \ No newline at end of file diff --git a/epy/python-libs/rope-0.9.4-py2.7.egg b/epy/python-libs/rope-0.9.4-py2.7.egg new file mode 100644 index 0000000..b621b88 Binary files /dev/null and b/epy/python-libs/rope-0.9.4-py2.7.egg differ diff --git a/epy/python-libs/ropemacs-0.7-py2.7.egg b/epy/python-libs/ropemacs-0.7-py2.7.egg new file mode 100644 index 0000000..d5a3731 Binary files /dev/null and b/epy/python-libs/ropemacs-0.7-py2.7.egg differ diff --git a/epy/python-libs/ropemode-0.2-py2.7.egg b/epy/python-libs/ropemode-0.2-py2.7.egg new file mode 100644 index 0000000..69ea782 Binary files /dev/null and b/epy/python-libs/ropemode-0.2-py2.7.egg differ diff --git a/epy/python-libs/site.py b/epy/python-libs/site.py new file mode 100644 index 0000000..a7166f1 --- /dev/null +++ b/epy/python-libs/site.py @@ -0,0 +1,83 @@ +def __boot(): + import sys, os, os.path + PYTHONPATH = os.environ.get('PYTHONPATH') + if PYTHONPATH is None or (sys.platform=='win32' and not PYTHONPATH): + PYTHONPATH = [] + else: + PYTHONPATH = PYTHONPATH.split(os.pathsep) + + pic = getattr(sys,'path_importer_cache',{}) + stdpath = sys.path[len(PYTHONPATH):] + mydir = os.path.dirname(__file__) + #print "searching",stdpath,sys.path + + for item in stdpath: + if item==mydir or not item: + continue # skip if current dir. on Windows, or my own directory + importer = pic.get(item) + if importer is not None: + loader = importer.find_module('site') + if loader is not None: + # This should actually reload the current module + loader.load_module('site') + break + else: + try: + import imp # Avoid import loop in Python >= 3.3 + stream, path, descr = imp.find_module('site',[item]) + except ImportError: + continue + if stream is None: + continue + try: + # This should actually reload the current module + imp.load_module('site',stream,path,descr) + finally: + stream.close() + break + else: + raise ImportError("Couldn't find the real 'site' module") + + #print "loaded", __file__ + + known_paths = dict([(makepath(item)[1],1) for item in sys.path]) # 2.2 comp + + oldpos = getattr(sys,'__egginsert',0) # save old insertion position + sys.__egginsert = 0 # and reset the current one + + for item in PYTHONPATH: + addsitedir(item) + + sys.__egginsert += oldpos # restore effective old position + + d,nd = makepath(stdpath[0]) + insert_at = None + new_path = [] + + for item in sys.path: + p,np = makepath(item) + + if np==nd and insert_at is None: + # We've hit the first 'system' path entry, so added entries go here + insert_at = len(new_path) + + if np in known_paths or insert_at is None: + new_path.append(item) + else: + # new path after the insert point, back-insert it + new_path.insert(insert_at, item) + insert_at += 1 + + sys.path[:] = new_path + +if __name__=='site': + __boot() + del __boot + + + + + + + + diff --git a/scripts/mypylint.sh b/epy/scripts/mypylint.sh similarity index 100% rename from scripts/mypylint.sh rename to epy/scripts/mypylint.sh diff --git a/scripts/package.py b/epy/scripts/package.py similarity index 100% rename from scripts/package.py rename to epy/scripts/package.py diff --git a/scripts/pylint-mod.py b/epy/scripts/pylint-mod.py similarity index 100% rename from scripts/pylint-mod.py rename to epy/scripts/pylint-mod.py diff --git a/scripts/tostarterkit.py b/epy/scripts/tostarterkit.py similarity index 100% rename from scripts/tostarterkit.py rename to epy/scripts/tostarterkit.py diff --git a/eshell/history b/eshell/history new file mode 100644 index 0000000..47ad8ec --- /dev/null +++ b/eshell/history @@ -0,0 +1,2 @@ +mc +exit diff --git a/eugeneai-theme-theme.el b/eugeneai-theme-theme.el new file mode 100644 index 0000000..2e8ee45 --- /dev/null +++ b/eugeneai-theme-theme.el @@ -0,0 +1,20 @@ +(deftheme eugeneai-theme + "Wheat color based theme, stolen in internet 2013-10-13.") + +(custom-theme-set-variables + 'eugeneai-theme + '(safe-local-variable-values (quote ((TeX-master . "dis") (py-master-file . "/path/to/interactivetest.py") (whitespace-line-column . 80) (lexical-binding . t)))) + '(show-paren-mode t) + '(tool-bar-mode nil)) + +(custom-theme-set-faces + 'eugeneai-theme + '(flyspell-duplicate ((t (:foreground "pale green")))) + '(flyspell-incorrect ((t (:foreground "orange red")))) + '(linum ((t (:inherit (shadow default) :background "black" :foreground "orange")))) + '(region ((((class color) (min-colors 88) (background dark)) (:background "orange3")))) + '(tex-verbatim ((t (:family "Ubuntu Mono")))) + '(tooltip ((((class color)) (:inherit variable-pitch :background "lightyellow" :foreground "black" :height 0.5)))) + '(default ((t (:inherit nil :stipple nil :background "gray20" :foreground "wheat1" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 101 :width normal :foundry "unknown" :family "Fira Sans Mono"))))) + +(provide-theme 'eugeneai-theme) diff --git a/extensions/eproject/eproject.cfg b/extensions/eproject/eproject.cfg deleted file mode 100644 index cc610ed..0000000 --- a/extensions/eproject/eproject.cfg +++ /dev/null @@ -1,44 +0,0 @@ -;; -*- mode: Lisp; -*- - -(setq prj-config - '(("project-name" . "eproject"))) - -(setq prj-tools - '(("Previous File" "-e eproject-prevfile" "M-left") - ("Next File" "-e eproject-nextfile" "M-right") - ("---") - ("Hello World" "echo \"Hello World!\"" "f1") - ("World Search" "-e (world-search-forward)" "f2") - ("---") - ("Explore Project" "nautilus --browser `pwd` &") - ("XTerm In Project" "xterm &") - )) - -(setq prj-files - '(("eproject.txt" 1 1) - ("eproject.el" 1 1) - ("eproject-config.el" 1 1) - )) - -(setq prj-functions - '( - (defun world-search-forward nil - (info "(emacs)word search") - (switch-to-buffer - (generate-new-buffer "*World Search*")) - (insert-buffer "*info*") - (save-excursion - (while - (re-search-forward "word" nil t) - (replace-match "world")))) - )) - -(unless prj-list - (setq prj-list - (list (list "eproject" - (directory-file-name eproject-directory) - ))) - (run-with-idle-timer - 1.0 nil - '(lambda () (message " *** Welcome to eproject ***")) - )) diff --git a/init.el b/init.el new file mode 100644 index 0000000..b5f983f --- /dev/null +++ b/init.el @@ -0,0 +1,1106 @@ +(if (eq window-system 'w32) + (progn + (if (file-directory-p "c:/GNU/bin") + (progn + (add-to-list 'exec-path "c:/GNU/bin") + ) + ) + (setq url-proxy-services '(("no_proxy" . "172.27.24.") + ("http" . "titan.cyber:ghbdtnbr@172.27.100.5:4444"))) + + ) + ) + +(custom-set-variables + '(load-prefer-newer t) + '(epy-load-yasnippet-p t) + ) + +(require 'package) + +; list the packages you want +(setq package-list '(auctex magit + auctex-latexmk + ace-jump-mode + color-theme + cursor-chg + d-mode + ace-jump-mode + ace-jump-buffer + ace-jump-zap + auto-complete + auto-complete-auctex + ; auto-dictionary-readme.txt + ; ediprolog + ; eide + ; enclose + fiplr + gh + goto-last-change + jedi + lua-mode + magit-find-file + magit-gh-pulls + markdown-mode+ + markdown-mode + python-environment + s + w3m + yasnippet + ;rw-ispell + ;rw-hunspell + ;rw-language-and-country-codes + htmlize + ;; flycheck + ;;company + ;;company-racer + ;;racer + ;; flycheck-rust + rust-mode + js2-mode +)) + +; list the repositories containing them +(setq package-archives '(("elpa" . "http://tromey.com/elpa/") + ("melpa" . "http://melpa.milkbox.net/packages/") + ("gnu" . "http://elpa.gnu.org/packages/") + ("marmalade" . "https://marmalade-repo.org/packages/"))) + +; activate all the packages (in particular autoloads) +(package-initialize) + +; fetch the list of packages available +(unless package-archive-contents + (package-refresh-contents)) + +; install the missing packages +(dolist (package package-list) + (unless (package-installed-p package) + (package-install package))) + +(setq magit-last-seen-setup-instructions "1.4.0") + +(require 'auctex-latexmk) +(auctex-latexmk-setup) + +;; Enable company globally for all mode +(global-company-mode) + +;; Reduce the time after which the company auto completion popup opens +(setq company-idle-delay 0.2) + +;; Reduce the number of characters before company kicks in +(setq company-minimum-prefix-length 2) + +;; ЗдеÑÑŒ указываем путь к бинарнику racer +(setq racer-cmd "/usr/bin/racer") + +;; Путь к иÑходникам Rust +(setq racer-rust-src-path "/home/eugeneai/.rust/src/") + +;; Load rust-mode when you open `.rs` files +(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-mode)) + +;;;(add-hook 'rust-mode-hook #'racer-mode) + +;; Setting up configurations when you load rust-mode +(add-hook 'rust-mode-hook + '(lambda () + ;; Enable racer + ;; (racer-activate) + (local-set-key (kbd "TAB") #'company-indent-or-complete-common) ; + + ;; Hook in racer with eldoc to provide documentation + (eldoc-mode) + + ;; Use flycheck-rust in rust-mode + (add-hook 'flycheck-mode-hook #'flycheck-rust-setup) + + ;; Use company-racer in rust mode + (set (make-local-variable 'company-backends) '(company-racer)) + + ;; Key binding to jump to method definition + (local-set-key (kbd "M-.") #'racer-find-definition) + + ;; Key binding to auto complete and indent + ;; (local-set-key (kbd "TAB") #'racer-complete-or-indent) + ) + ) + +(add-hook 'racer-mode-hook #'eldoc-mode) + +; (setq-default TeX-master nil) +(custom-set-variables +; '(TeX-install-font-lock 'tex-font-setup) + '(TeX-auto-save t) + '(TeX-parse-self t) + '(TeX-master nil) + '(TeX-save-query nil) + '(TeX-source-correlate-method (quote synctex)) + '(TeX-source-correlate-mode t) + '(TeX-source-correlate-start-server (quote ask))) + +(add-hook 'LaTeX-mode-hook 'LaTeX-math-mode) +(add-hook 'LaTeX-mode-hook 'turn-on-reftex) +(add-hook 'LaTeX-mode-hook 'turn-off-auto-fill) +(add-hook 'LaTeX-mode-hook 'turn-on-visual-line-mode) +(add-hook 'LaTeX-mode-hook 'turn-on-flyspell) + +(setq reftex-plug-into-AUCTeX t) + +(require 'cursor-chg) +(setq curchg-default-cursor-color "LightSkyBlue1") +(setq curchg-input-method-cursor-color "red") +(setq curchg-default-cursor-type '(hbar . 5)) +(change-cursor-mode 1) ; On for overwrite/read-only/input mode +(toggle-cursor-type-when-idle 1) ; On when idle + +(setq windowed-system (or (eq window-system 'x) (eq window-system 'w32))) +(setq win32-system (eq window-system 'w32)) + +(menu-bar-mode 0) +(setq inhibit-startup-message t) + +(add-to-list 'load-path (expand-file-name "~/.emacs.d/lisp")) +(add-to-list 'load-path (expand-file-name "~/.emacs.d/epy")) + +;; magnars cool setup +;; Set path to .emacs.d +;;(setq dotfiles-dir (file-name-directory +;; (or (buffer-file-name) load-file-name))) +(setq dotfiles-dir (expand-file-name "~/.emacs.d/")) + + +;; Set path to dependencies +(setq site-lisp-dir (expand-file-name "site-lisp" dotfiles-dir)) +(setq ext-lisp-dir (expand-file-name "epy/extensions" dotfiles-dir)) + +;; Set up load path +;;(add-to-list 'load-path dotfiles-dir) +(add-to-list 'load-path site-lisp-dir) + +;; Settings for currently logged in user +(setq user-settings-dir (concat user-emacs-directory "users/" user-login-name)) +(add-to-list 'load-path user-settings-dir) + +;; Add external projects to load path +(dolist (project (directory-files site-lisp-dir t "\\w+")) + (when (file-directory-p project) + (add-to-list 'load-path project))) + +(dolist (project (directory-files ext-lisp-dir t "\\w+")) + (when (file-directory-p project) + (add-to-list 'load-path project))) + +(add-to-list 'load-path ".") + +;; Keep emacs Custom-settings in separate file +(if t ;; windowed-system + (progn + (if windowed-system + (progn + (tool-bar-mode 0) + (scroll-bar-mode 0) + ) + ) + (if win32-system + (progn + (setq custom-file (expand-file-name "custom-w32.el" dotfiles-dir)) + ) + (progn + (setq custom-file (expand-file-name "custom.el" dotfiles-dir)) + ) + ) + ) + (setq custom-file (expand-file-name "custom-nw.el" dotfiles-dir)) + ) + +;; Write backup files to own directory +(setq backup-directory-alist `(("." . ,(expand-file-name + (concat dotfiles-dir "backups"))))) +(require 'auto-complete) + +(require 'linum) + +;;(global-linum-mode 1) +;; (global-auto-complete-mode 1) +(define-globalized-minor-mode real-global-auto-complete-mode + auto-complete-mode (lambda () + (if (not (minibufferp (current-buffer))) + (auto-complete-mode 1)) + )) +(real-global-auto-complete-mode t) + +(if win32-system + (setenv "PYMACS_PYTHON" "c:/python27/python.exe") + (setenv "PYMACS_PYTHON" "python2") +) + +(load-file (expand-file-name "epy/epy-init.el" dotfiles-dir)) + +(if + t ;;windowed-system + (setq linum-format "%4d ") + (progn + (setq linum-format "%3d ") + (global-linum-mode 1) + ) +) + +(autoload 'run-prolog "prolog" "Start a Prolog sub-process." t) +(autoload 'prolog-mode "prolog" "Major mode for editing Prolog programs." t) +(autoload 'mercury-mode "prolog" "Major mode for editing Mercury programs." t) +(setq prolog-system 'swi) ;; swi +(setq auto-mode-alist (append '(("\\.pl$" . prolog-mode) + ("\\.pro$" . prolog-mode) + ("\\.m$" . mercury-mode) + ("\\.P$" . prolog-mode) + ("\\.tex$" . latex-mode) + ) + auto-mode-alist)) +(add-hook 'prolog-mode-hook 'auto-complete-mode) +(add-hook 'd-mode-hook 'auto-complete-mode) + + +(autoload 'flyspell-mode "flyspell" "On-the-fly spelling checker." t) +(autoload 'flyspell-delay-command "flyspell" "Delay on command." t) +(autoload 'tex-mode-flyspell-verify "flyspell" "" t) + +(global-set-key (kbd "C-c q") 'auto-fill-mode) + + +(autoload 'markdown-mode "markdown-mode.el" + "Major mode for editing Markdown files" t) +(setq auto-mode-alist + (cons '("\.md" . markdown-mode) auto-mode-alist)) + +(autoload 'vala-mode "vala-mode" "Major mode for editing Vala code." t) +(add-to-list 'auto-mode-alist '("\.vala$" . vala-mode)) +(add-to-list 'auto-mode-alist '("\.vapi$" . vala-mode)) +(add-to-list 'file-coding-system-alist '("\.vala$" . utf-8)) +(add-to-list 'file-coding-system-alist '("\.vapi$" . utf-8)) + +;;Setting up tabbar +;;(require 'tabbar) +;;(tabbar-mode) + + +(require 'recentf) +(setq recentf-auto-cleanup 'never) ;; disable before we start recentf! +(recentf-mode 1) +(setq +;; recentf-menu-path '("File") +;; recentf-menu-title "Recent" + recentf-max-saved-items 200 +;; recentf-max-menu-items 20 + ) +(global-set-key "\C-x\ \C-r" 'recentf-open-files) + +(if + windowed-system + (progn + ;(require 'tabbar) + ;(tabbar-mode) + ;(menu-bar-mode 0) + (set-fringe-style '(0 . 0)) ; no fringes atall + (mouse-wheel-mode t) + (global-font-lock-mode t) + (setq font-lock-maximum-decoration t) + ) + (progn + (setq window-numbering-assign-func + (lambda () (when (equal (buffer-name) "*Calculator*") 9))) + ) +) + + +(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup) +(defun my-minibuffer-setup () + (set (make-local-variable 'face-remapping-alist) + '((default :height 1.0)))) ; just for a while + +(setq-default + default-truncate-lines t + blink-cursor-alist '((t . hollow)) + user-full-name "Evgeny Cherkashin" + user-mail-address "eugeneai@irnok.net" + column-number-mode t + line-number-mode t + page-delimiter "^\\s *\n\\s *" + minibuffer-max-depth nil + display-time-day-and-date t + frame-title-format '(buffer-file-name "%f" "%b") +) + +;; goto-matching-paren +;; ------------------- +;; If point is sitting on a parenthetic character, jump to its match. +;; This matches the standard parenthesis highlighting for determining which +;; one it is sitting on. +;; +(defun goto-matching-paren () + "If point is sitting on a parenthetic character, jump to its match." + (interactive) + (cond ((looking-at "\\s\(") (forward-list 1)) + ((progn + (backward-char 1) + (looking-at "\\s\)")) (forward-char 1) (backward-list 1)))) +(define-key global-map (kbd "C-x p p") 'goto-matching-paren) ; Bind to C-z p + +;;; Stefan Monnier . It is the opposite of fill-paragraph +(defun unfill-paragraph () + "Takes a multi-line paragraph and makes it into a single line of text." + (interactive) + (let ((fill-column (point-max))) + (fill-paragraph nil))) + +(defun reconstruct-paragraph () + "Takes a multi-line paragraph and makes it into a single line of text." + (interactive) + (let ((fill-column (point-max))) + (fill-paragraph nil) + ) + (replace-regexp "\\(\\w+\\)-\\s-+\\(\\w+\\)" "\\1\\2" nil (line-beginning-position) (line-end-position)) + (replace-regexp "\\s-*вЂ\â€" "~--" nil (line-beginning-position) (line-end-position)) + (replace-regexp "\\s—" "~--" nil (line-beginning-position) (line-end-position)) + (replace-regexp "\\(\\w+\\)-\\(\\w+\\)" "\\1\"=\\2" nil (line-beginning-position) (line-end-position)) + (replace-regexp "\\.\\.\\." "\\\\ldots{}" nil (line-beginning-position) (line-end-position)) + (replace-regexp "\\[\\([[:digit:]]+\\)\\]" "\\\\cite{b\\1}" nil (line-beginning-position) (line-end-position)) + ;(replace-regexp "\\(\\w\\|\\.\\):" "\\1\\\\,:" nil (line-beginning-position) (line-end-position)) + (replace-regexp "\\([тТ]\\.\\)\\s-*\\(\\w\\.\\)" "\\1~\\2" nil (line-beginning-position) (line-end-position)) + (replace-regexp "\\([[:upper:]]\\.\\)\\s-*\\([[:upper:]]\\.\\)\\s-+\\([[:upper:]]\\w*\\)" "\\1~\\2~\\3" nil (line-beginning-position) (line-end-position)) + (replace-regexp "\\([[:upper:]]\\.\\)\\s-+\\([[:upper:]]\\w*\\)" "\\1~\\2" nil (line-beginning-position) (line-end-position)) + ;(replace-regexp "\"\\(\\w+\\)" "<<\1" nil (line-beginning-position) (line-end-position)) + ;(replace-regexp "\\(\\w+\\)\"" "\1>>" nil (line-beginning-position) (line-end-position)) + ;(replace-regexp "\"\\(\\.\\)\"" "<<\1>>" nil (line-beginning-position) (line-end-position)) + ;(replace-regexp "\\s-+" "_") + ) + +(defun reconstruct-minted () + "From cursor till '\end{' performs text cleaning." + (interactive) + (let ((endpos (point))) + (save-excursion + (goto-char (mark)) + (beginning-of-line) + (while (< (point) endpos) + ;; (funcall fun (buffer-substring (line-beginning-position) (line-end-position))) + (reconstruct-minted-line) + ) + ) + ) + ) + +(defun reconstruct-minted-line () + (interactive) + (beginning-of-line) + (replace-regexp "\\\\textquotedbl{}" "\"" nil (line-beginning-position) (line-end-position)) + (replace-regexp "#doctest:.*$" "" nil (line-beginning-position) (line-end-position)) + (replace-regexp "^\\.\\.\\." " " nil (line-beginning-position) (line-end-position)) + (replace-regexp "\\~" " " nil (line-beginning-position) (line-end-position)) + (replace-regexp "\\\\" "" nil (line-beginning-position) (line-end-position)) + (replace-regexp "{\\[}" "[" nil (line-beginning-position) (line-end-position)) + (replace-regexp "{\\]}" "]" nil (line-beginning-position) (line-end-position)) + (forward-line 1) + ; #doctest: +ELLIPSIS + ) + +;; Handy key definition +(define-key global-map [f9] 'reconstruct-paragraph) +(define-key global-map [f12] 'reconstruct-minted-line) + +(require 'window-numbering) +(window-numbering-mode 1) +(require 'ido) +(require 'highlight-80+) +(highlight-80+-mode) + + +(add-to-list 'auto-mode-alist '("\\.zcml\\'" . xml-mode)) +(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode)) + +;;;;; key bindings + +(global-set-key (kbd "C-x e") 'erase-buffer) +(global-set-key (kbd "C-") 'keyboard-escape-quit) +(global-unset-key (kbd "--")) +(global-set-key (kbd "C-q") 'quoted-insert) +(global-set-key (kbd "C-z") 'undo) + +(global-set-key (kbd "s-") 'next-buffer) +(global-set-key (kbd "s-") 'previous-buffer) +(global-set-key (kbd "C-") 'open-next-line) + +(defun kill-current-buffer () + (interactive) + (kill-buffer (current-buffer))) + +(global-set-key (kbd "C-x C-k") 'kill-current-buffer) +(global-set-key (kbd "C-x c") 'compile) +(global-set-key (kbd "C-x h") 'view-url) +(global-set-key (kbd "C-x M-m") 'shell) +;(global-set-key [f7] 'split-window-vertically) +;(global-set-key [f8] 'delete-other-windows) +;(global-set-key [f9] 'split-window-horizontally) + +(setq visible-bell nil) + +(setq echo-keystrokes 0.1 + font-lock-maximum-decoration t + inhibit-startup-message t + transient-mark-mode t + color-theme-is-global t + delete-by-moving-to-trash t + shift-select-mode nil + mouse-yank-at-point t + require-final-newline t + truncate-partial-width-windows nil + uniquify-buffer-name-style 'forward + whitespace-style '(trailing lines space-before-tab + indentation space-after-tab) + whitespace-line-column 80 + ediff-window-setup-function 'ediff-setup-windows-plain + xterm-mouse-mode t + ) + +(add-to-list 'safe-local-variable-values '(lexical-binding . t)) +(add-to-list 'safe-local-variable-values '(whitespace-line-column . 80)) + +(set-default 'indent-tabs-mode nil) +(set-default 'indicate-empty-lines t) +(set-default 'imenu-auto-rescan nil) + + +(defalias 'yes-or-no-p 'y-or-n-p) +(random t) ;; Seed the random-number generator + +(set-terminal-coding-system 'utf-8) +(set-keyboard-coding-system 'utf-8) +(prefer-coding-system 'utf-8) +(ansi-color-for-comint-mode-on) + +(when (> emacs-major-version 21) + (ido-mode t) + (setq ido-enable-prefix nil + ido-enable-flex-matching t + ido-create-new-buffer 'always + ido-use-filename-at-point t + ido-max-prospects 10)) + +(global-set-key [C-f1] 'bookmark-set) +(global-set-key [f1] 'bookmark-jump) + +;; Strange colous + +(setq inhibit-startup-message t) ; Don't want any startup message +;(setq make-backup-files nil) ; Don't want any backup files +;(setq auto-save-list-file-name nil) ; Don't want any .saves files +;(setq auto-save-default nil) ; Don't want any auto saving + +(setq search-highlight t) ; Highlight search object +(setq query-replace-highlight t) ; Highlight query object +(setq mouse-sel-retain-highlight t) ; Keep mouse high-lightening + +;;; lets you use Ido with imenu. +(require 'imenu+) +(add-hook 'python-mode-hook 'imenu-add-defs-to-menubar) +(global-set-key [S-mouse-3] 'imenu) + +(require 'highlight-indentation) +(add-hook 'python-mode-hook 'highlight-indentation) +(add-hook 'python-mode-hook (lambda ()(setq skeleton-pair nil))) + +;;; Set some more + +(add-hook 'before-save-hook 'delete-trailing-whitespace) + +(defun annotate-pdb () + (interactive) + (highlight-lines-matching-regexp "import pdb") + (highlight-lines-matching-regexp "pdb.set_trace()")) +(add-hook 'python-mode-hook 'annotate-pdb) + +(defun python-add-breakpoint () + (interactive) + (newline-and-indent) + (insert "import pdb; pdb.set_trace()") + (newline-and-indent) + (highlight-lines-matching-regexp "^[ ]*import pdb; pdb.set_trace()")) + +(defun python-add-pubreakpoint () + (interactive) + (newline-and-indent) + (insert "import pudb; pu.db") + (newline-and-indent) + (highlight-lines-matching-regexp "^[ ]*import pudb; pu.db")) + +(add-hook 'python-mode-hook '(lambda () (define-key python-mode-map (kbd "C-c C-t") 'python-add-breakpoint))) +(add-hook 'python-mode-hook '(lambda () (define-key python-mode-map (kbd "C-c C-y") 'python-add-pubreakpoint))) + +(add-hook 'python-mode-hook '(lambda () + (define-key python-mode-map (kbd "C-c C-y") 'python-add-pubreakpoint) + (electric-indent-local-mode -1) + (local-set-key (kbd "C-j") #'newline-and-indent) + )) + +(defun tex-add-russian-dash () + (interactive) + (insert "~-- ")) + +;(add-hook 'late-mode-hook (lambda () +; (local-set-key (kbd "C-=") #'tex-add-russian-dash))) + +(defun tex-add-verb-environment () + (interactive) + (open-next-line 1) + (insert "{\\tt%") + (open-next-line 1)(beginning-of-line) + (insert "\\begin{verbatim}") + (open-next-line 1) + (open-next-line 1) + (insert "\\end{verbatim}%") + (open-next-line 1)(beginning-of-line) + (insert "}%") + (backward-char 2) + (forward-line -2) + ) + +(global-set-key (kbd "C-=") 'tex-add-russian-dash) +(global-set-key (kbd "C-c C-=") 'tex-add-verb-environment) + +(defun my-ttt () + (erase-buffer) + (face-remap-add-relative 'default '( + ; :family "Monospace" + ; :height 160 ;Seseg + :height 88 + )) +) + +(add-hook 'comint-mode-hook 'my-ttt) +(add-hook 'compilation-mode-hook 'my-ttt) +(add-hook 'gdb-locals-mode-hook 'my-ttt) +(add-hook 'gdb-frames-mode-hook 'my-ttt) +(add-hook 'gdb-registers-mode-hook 'my-ttt) + + +;; vala +(autoload 'vala-mode "vala-mode" "Major mode for editing Vala code." t) +(add-to-list 'auto-mode-alist '("\\.vala$" . vala-mode)) +(add-to-list 'auto-mode-alist '("\\.vapi$" . vala-mode)) +(add-to-list 'file-coding-system-alist '("\\.vala$" . utf-8)) +(add-to-list 'file-coding-system-alist '("\\.vapi$" . utf-8)) + +;; JavaScript + +(add-to-list 'auto-mode-alist '("\\.json$" . js-mode)) +(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode)) +;(add-hook 'js-mode-hook 'js2-minor-mode) +(add-hook 'js2-mode-hook 'ac-js2-mode) +(add-to-list 'interpreter-mode-alist '("node" . js2-mode)) +(setq js2-highlight-level 3) + +(add-hook 'js2-mode-hook 'skewer-mode) +(add-hook 'css-mode-hook 'skewer-css-mode) +(add-hook 'html-mode-hook 'skewer-html-mode) + +(load custom-file) + +(if + t ;; windowed-system + (progn + ;; This script is set for a `text-scale-mode-step` of `1.04` + (setq text-scale-mode-step 1.2) + ;; + ;; List: `Sub-Zoom Font Heights per text-scale-mode-step` + ;; eg. For a default font-height of 120 just remove the leading `160 150 140 130` + (defvar sub-zoom-ht (list 160 150 140 130 120 120 110 100 100 90 80 80 80 80 70 70 60 60 50 50 50 40 40 40 30 20 20 20 20 20 20 10 10 10 10 10 10 10 10 10 10 5 5 5 5 5 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1)) + (defvar sub-zoom-len (safe-length sub-zoom-ht)) + (defvar def-zoom-ht (car sub-zoom-ht)) + (set-face-attribute 'default nil :height def-zoom-ht) + + ;; Adjust line number fonts. + + (setq my-def-linum-text-height + (face-attribute 'default :height) + ) + + (defun text-scale-adjust-zAp () + (interactive) + (text-scale-adjust 0) + (set-face-attribute 'linum nil :height my-def-linum-text-height) + ) + + (defun text-scale-decrease-zAp () + (interactive) + (text-scale-decrease 1) + (set-face-attribute 'linum nil :height my-def-linum-text-height) + ) + + (defun text-scale-increase-zAp () + (interactive) + (text-scale-increase 1) + (set-face-attribute 'linum nil :height my-def-linum-text-height) + ) + + ;; Zoom font via Numeric Keypad + + (define-key global-map (kbd "") 'text-scale-increase-zAp) + (define-key global-map (kbd "") 'text-scale-decrease-zAp) + (define-key global-map (kbd "") 'text-scale-adjust-zAp) + (define-key global-map (kbd "") 'text-scale-increase-zAp) + (define-key global-map (kbd "") 'text-scale-decrease-zAp) + (define-key global-map (kbd "") 'text-scale-increase-zAp) + (define-key global-map (kbd "") 'text-scale-decrease-zAp) + + ;; (set-scroll-bar-mode 'right) ; replace 'right with 'left to place it to the left + (setq popup-use-optimized-column-computation nil) ; May be tie menu zise to default text size. + ;; (ac-fuzzy-complete) + ;; (ac-use-fuzzy) + ;; (add-hook 'after-make-frame-functions 'fullscreen-toggle) + (defun toggle-fullscreen-1 (&optional f) + (interactive) + (let ((current-value (frame-parameter nil 'fullscreen))) + (set-frame-parameter nil 'fullscreen + (if (equal 'fullboth current-value) + (if (boundp 'old-fullscreen) old-fullscreen nil) + (progn (setq old-fullscreen current-value) + 'fullboth) + ) + ;(menu-bar-mode 0) + ) + ) + ) + (global-set-key [f11] 'toggle-frame-fullscreen) + ;;(global-set-key (kbd "C-c f") 'toggle-fullscreen) + (if (not win32-system) + (progn + (defun maximize-window (&optional f) + (interactive) + (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 + '(2 "_NET_WM_STATE_MAXIMIZED_VERT" 0)) + (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 + '(2 "_NET_WM_STATE_MAXIMIZED_HORZ" 0))) + + ;;; (toggle-fullscreen) + ;;; (maximize-window) + )) + ) + (progn + (set-face-background 'region "blue") ; Set region background color + (set-face-foreground 'region "wheat1") ; Set region background color + (set-face-background 'linum "gray10") ; Set region background color + (set-face-foreground 'linum "gold") ; Set region background color + ) + ) + + +(defun python-shell-get-or-create-process () + "Get or create an inferior Python process for current buffer and return it." + (let* ((old-buffer (current-buffer)) + (dedicated-proc-name (python-shell-get-process-name t)) + (dedicated-proc-buffer-name (format "*%s*" dedicated-proc-name)) + (global-proc-name (python-shell-get-process-name nil)) + (global-proc-buffer-name (format "*%s*" global-proc-name)) + (dedicated-running (comint-check-proc dedicated-proc-buffer-name)) + (global-running (comint-check-proc global-proc-buffer-name)) + (current-prefix-arg 4)) + (when (and (not dedicated-running) (not global-running)) + (if (run-python t (python-shell-parse-command)) + (setq dedicated-running t) + (setq global-running t))) + ;; Always prefer dedicated + (switch-to-buffer old-buffer) + (get-buffer-process (if dedicated-running + dedicated-proc-buffer-name + global-proc-buffer-name)))) + + +(require 'jump-char) + +(global-set-key [(meta \])] 'jump-char-forward) +(global-set-key [(meta \[)] 'jump-char-backward) + +(defun set-input-method-english () + (interactive) + (if current-input-method (toggle-input-method)) + ) + +(defun latex-b-slash () + (interactive) + (set-input-method-english) + (insert "\\") +) + +;; (set-background-color "wheat3") ; Set emacs bg color + +;;(toggle-fullscreen) + +;; Adjust line number fonts. + +(defun dollar-equation () + (interactive) + (set-input-method-english) + (insert "$$") + (backward-char) + (set-input-method-english) +) + +(defun latex-dollar-hack () + (interactive) + (local-set-key (kbd "C-4") 'dollar-equation) + ) + +(defun turn-off-auto-fill () + (interactive) + (auto-fill-mode 0)) + +(add-hook 'text-mode-hook 'turn-on-auto-fill) +(add-hook 'text-mode-hook 'turn-on-flyspell) + +(add-hook 'text-mode-hook 'turn-on-visual-line-mode) +(add-hook 'diff-mode-hook 'turn-on-visual-line-mode) +(add-hook 'latex-mode-hook 'turn-off-auto-fill) +(add-hook 'latex-mode-hook 'turn-on-visual-line-mode) +(add-hook 'latex-mode-hook 'turn-on-flyspell) + +;;(add-hook 'latex-mode-hook 'highlight-changes-mode) + +(global-set-key (kbd "C-") 'toggle-input-method) +(global-set-key (kbd "") 'toggle-input-method) ;; for windows. + +(global-set-key [(meta m)] 'jump-char-forward) +(global-set-key [(shift meta m)] 'jump-char-backward) +(global-set-key (kbd "") 'scroll-lock-mode) +(put 'downcase-region 'disabled nil) + + +;; auto-language + +(defun my-char-lang-guess (arg) + (let ( + (ch-cat + (get-char-code-property + arg + 'general-category) + ) + ) + (cond + ( + (or + (eq ch-cat 'Ll) + (eq ch-cat 'Lu) + ) + (car + (split-string + (get-char-code-property + arg + 'name + ))) + + ) + (t "NONE") + ) + ) + ) + +(defun my-map (arg) + (cond + ((equal arg "NONE") + "LATIN" + ) + (t + arg + ) + ) + ) + +(defun my-point-lang-guess () + (mapcar #'my-map (my-l-r-props)) +) + +(defun my-l-r-props () + (list + (my-char-lang-guess (preceding-char)) + (my-char-lang-guess (following-char)) + ) + ) + +(defun my-scan-to-word () + (save-excursion + (while + (and + (not (bobp)) + (or + (equal + (my-l-r-props) + (list "NONE" "NONE") + ) + ) + ) + (backward-char) + ) + ;() + (my-point-lang-guess) + ) + ) + +(defun auto-language-environment () + (interactive) + ;; (print last-command this-command) + (cond + ( + (and + (eq this-command 'self-insert-command) + (or + (eq last-command 'toggle-input-method) + (eq last-command 'set-input-method) + ) + ) + t + ) + ((eq this-command 'dollar-equation) + (set-input-method-english) + t) + ( + (or + (eq this-command 'toggle-input-method) + (eq this-command 'set-input-method) + ) + t + ) + ( + (and + (eq this-command 'self-insert-command) + (eq last-command 'self-insert-command)) + t + ) + ( + (equal + (my-scan-to-word) + (list "LATIN" "LATIN") + ) + (set-input-method-english) + t + ) + ( + t + (set-input-method "russian-computer") + t + ) + (t + (set-input-method-english) + ) + ) + ) + +(defun latex-12-hacks () + (latex-dollar-hack) + ; (add-hook 'post-command-hook 'auto-language-environment) + ) + +(add-hook 'LaTeX-mode-hook 'latex-12-hacks) + +(global-set-key (kbd "C-`") 'linum-mode) +(put 'scroll-left 'disabled nil) + +;; Patching wrong scrolllock behaviour +(defun scroll-lock-next-line (&optional arg) + "Scroll up ARG lines keeping point fixed." + (interactive "p") + (or arg (setq arg 1)) + (scroll-lock-update-goal-column) + (if (pos-visible-in-window-p (point-max)) + (progn + (next-line arg) + (print "vis-p") + (print arg) + ) + (progn + (scroll-up arg) + (next-line (- arg)) + (print arg) + (print "not-vis-p") + ) + ) + (scroll-lock-move-to-column scroll-lock-temporary-goal-column) + ) + +(load "server") +(unless (server-running-p) (server-start)) + +(setq visible-bell 1) + +(defvar gud-overlay +(let* ((ov (make-overlay (point-min) (point-min)))) +(overlay-put ov 'face 'secondary-selection) +ov) +"Overlay variable for GUD highlighting.") + +(defadvice gud-display-line (after my-gud-highlight act) +"Highlight current line." +(let* ((ov gud-overlay) +(bf (gud-find-file true-file))) +(save-excursion + (set-buffer bf) + (move-overlay ov (line-beginning-position) (line-end-position) + (current-buffer))))) + +(defun gud-kill-buffer () +(if (eq major-mode 'gud-mode) +(delete-overlay gud-overlay))) + +(add-hook 'kill-buffer-hook 'gud-kill-buffer) +(add-hook 'gdb-mode-hook '(lambda () + ;(new-frame) + ;(switch-to-buffer "**gdb**") + ;(tool-bar-mode 1) + (gdb-many-windows) + )) +;;------------------------------------------------------------- + +(put 'erase-buffer 'disabled nil) + +(require 'compile) +(add-to-list + 'compilation-error-regexp-alist + '("^\\([^ \n]+\\)(\\([0-9]+\\)): \\(?:error\\|.\\|warnin\\(g\\)\\|remar\\(k\\)\\)" + 1 2 nil (3 . 4))) + +(require 'goto-last-change) +(global-set-key (kbd "C-x C-\\") 'goto-last-change) + +;; Some additional features +(defalias 'qrr 'query-replace-regexp) + +;; Workaround rope hooks error + +(if (not (functionp 'rope-after-save-actions)) + (defun rope-after-save-actions ()) + ) +(if (not (functionp 'rope-before-save-actions)) + (defun rope-before-save-actions ()) +) + +(require 'rw-language-and-country-codes) +(require 'rw-ispell) +(require 'rw-hunspell) +(add-to-list 'ispell-local-dictionary-alist '("russian" + "[ÐБВГДЕÐЖЗИЙКЛМÐОПРСТУФХЦЧШЩЬЫЪЭЮЯабвгдеёжзийклмнопрÑтуфхцчшщьыъÑÑŽÑ]" + "[^ÐБВГДЕÐЖЗИЙКЛМÐОПРСТУФХЦЧШЩЬЫЪЭЮЯабвгдеёжзийклмнопрÑтуфхцчшщьыъÑÑŽÑ]" + "[-]" nil ("-d" "ru_RU") nil utf-8) +) + +(add-to-list 'ispell-local-dictionary-alist '("english" + "[A-Za-z]" "[^A-Za-z]" + "[']" nil ("-d" "en_US") nil iso-8859-1) +) + +;(setq ispell-program-name "hunspell") +(setq ispell-program-name (executable-find "hunspell")) +(setq ispell-really-aspell nil + ispell-really-hunspell t) +(setq ispell-dictionary "russian") ;"ru_RU_hunspell") +;; The following is set via custom +(custom-set-variables + '(rw-hunspell-default-dictionary "russian") ;"ru_RU_hunspell") + '(rw-hunspell-dicpath-list (quote ("/usr/share/hunspell"))) + '(rw-hunspell-make-dictionary-menu t) + '(rw-hunspell-use-rw-ispell t) + ) + +(if (eq window-system 'w32) + (progn + (custom-set-variables + '(rw-hunspell-dicpath-list (quote ("c:/GNU/share/hunspell"))) + ) + ) + ) + +;(setq ispell-program-name "c:/GNU/bin/aspell") +;(setq ispell-program-name "aspell") +;(setq ispell-personal-dictionary "C:/GNU/custom.ispell") + +;; (setq ispell-extra-args +;; '("--data-dir" "C:/GNU/data" +;; "--dict-dir" "C:/GNU/dict" +;; ) +;; ) + +(require 'ispell) + +(defun fd-switch-dictionary() + (interactive) + (let* ((dic ispell-current-dictionary) + (change (if (string= dic "russian") "english" "russian"))) + (ispell-change-dictionary change) + (message "Dictionary switched from %s to %s" dic change) + )) + +;(require 'ispell-multi) +;(require 'flyspell-babel) + +;(autoload 'flyspell-babel-setup "flyspell-babel") +;(add-hook 'latex-mode-hook 'flyspell-babel-setup) + +(global-set-key (kbd "") 'fd-switch-dictionary) +(global-set-key (kbd "") 'ispell-word) +(put 'upcase-region 'disabled nil) + +(autoload + 'ace-jump-mode + "ace-jump-mode" + "Emacs quick move minor mode" + t) + +(define-key global-map (kbd "C-c SPC") 'ace-jump-mode) + +;; enable a more powerful jump back function from ace jump mode +(autoload + 'ace-jump-mode-pop-mark + "ace-jump-mode" + "Ace jump back:-)" + t) +(eval-after-load "ace-jump-mode" + '(ace-jump-mode-enable-mark-sync)) +(define-key global-map (kbd "C-x SPC") 'ace-jump-mode-pop-mark) + +(global-set-key (kbd "C-x f") 'fiplr-find-file) + +;; Standard Jedi.el setting + +; does not work now. +;(add-hook 'python-mode-hook 'jedi:setup) +;(setq jedi:complete-on-dot t) + +;; Type: +;; M-x package-install RET jedi RET +;; M-x jedi:install-server RET +;; Then open Python file. + +;; Save point position between sessions +(require 'saveplace) +(setq-default save-place t) +(setq save-place-file (expand-file-name ".places" user-emacs-directory)) + +(global-set-key "\C-x\ \C-m" 'magit-status) + +(setq ring-bell-function + (lambda () + (unless (memq this-command + '(isearch-abort abort-recursive-edit exit-minibuffer keyboard-quit)) + (ding)))) + +;; Multitran dictionary lookup +(defun multitran-lookup-english (keyword) + (interactive (list (thing-at-point 'word))) + (switch-to-buffer-other-window + (eww + ;; (w3m-goto-url + (concat "http://multitran.ru/c/m.exe?l1=1&s=" keyword "&%CF%EE%E8%F1%EA=%CF%EE%E8%F1%EA") + ) + ) + ;;(run-at-time 4 nil 'iconify-frame) + ) + +(global-set-key (kbd "C-c m") 'multitran-lookup-english) diff --git a/lisp/flyspell-babel.el b/lisp/flyspell-babel.el new file mode 100644 index 0000000..311aade --- /dev/null +++ b/lisp/flyspell-babel.el @@ -0,0 +1,482 @@ +;; flyspell-babel.el -- Switch flyspell language according to LaTeX +;; Babel commands +;; +;; Copyright (C) 2004 P J Heslin +;; +;; Author: Peter Heslin +;; URL: http://www.dur.ac.uk/p.j.heslin/Software/Emacs +;; Version: 3.2 +;; +;; 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, 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. +;; +;; If you do not have a copy of the GNU General Public License, you +;; can obtain one by writing to the Free Software Foundation, Inc., 59 +;; Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +;;; Installation: +;; +;; Flyspell is an Emacs package that highlights misspelled words as +;; you type; Babel is the standard mechanism for switching languages +;; in LaTeX. There are a number of Emacs packages available that will +;; try to guess the current language of a buffer or part of a buffer, +;; and make flyspell switch to a different dictionary; but I didn't +;; find one that used the explicit language-switching commands +;; available in a LaTeX file for this purpose. This package makes +;; flyspell use the correct dictionary for the language used in each +;; part of a LaTeX file. There are some restrictions on the usage of +;; Babel commands, on which see below. +;; +;; flyspell-babel requires ispell-multi to be installed; it may be +;; found in the same directory indicated by the URL above. It also +;; needs flyspell to be installed (version 1.7f or better) and +;; flyspell-mode to be active. If you are using Emacs 21.3 or +;; earlier, you will need to upgrade to ispell.el version 3.6, +;; available from http://www.kdstevens.com/~stevens/ispell-page.html. +;; +;; To use this file, put it somewhere in your load-path, and add this +;; to your .emacs file: +;; +;; (autoload 'flyspell-babel-setup "flyspell-babel") +;; (add-hook 'latex-mode-hook 'flyspell-babel-setup) +;; +;; You will need to reload flyspell-babel.el if you install any new +;; ispell languages or language aliases. +;; +;; I have only tested this with GNU Emacs. + +;;; Commentary: +;; +;; This package examines the LaTeX code around point to discover the +;; language of the current text, and then it caches that value in a +;; text-property. This means that, if you modify or add a Babel +;; command to change the language of some text, the current language +;; may be out of sync with the cached value. In this case, you can +;; just stop typing for a bit, and the surrounding text will be +;; re-parsed, and the new, correct language should be determined. The +;; length of time that Emacs is idle before this re-parsing happens is +;; configurable via the variable flyspell-babel-delay (default is 5 +;; seconds). +;; +;; The parsing done by this package has its limits limited, and so it +;; will not work with arbitrary LaTeX code. I hope that these +;; restrictions will not in practice impinge on the typical usage of +;; most people. The first language declaration is usually determined +;; by the final language option passed to the babel \usepackage +;; command, which takes effect after \begin{document}. Thereafter, +;; you can switch the declared language with \selectlanguage +;; statements, otherlanguage environments, and \foreignlanguage +;; commands. You can also define your own language-switching +;; commands, and register these with flyspell-babel. +;; +;; This package does not understand complex LaTeX constructs, such as +;; \input. If you want to set the default language for a particular +;; file (for example, one that has no Babel declaration, but is going +;; to be \input into a file that does), you can just put a redundant +;; \selectlanguage declaration at the start of the file. You can +;; limit the scope of a \selectlanguage declaration by putting an +;; opening brace immediately before it, and flyspell-babel will +;; respect that scoping, but not otherwise, since that would make the +;; task of parsing too complex. +;; +;; By default, an ispell dictionary is invoked with the same name as +;; the current Babel language or dialect, which works in many cases. +;; If your ispell has a different name for that language, you have two +;; options. You can make ispell recognize the Babel name by adding +;; symlinks under that name in your Ispell directory. Alternatively, +;; you can customize flyspell-babel-to-ispell-alist, which maps Babel +;; languages and dialects to Ispell language names. If you map a +;; language to 'nil, that means not to spell-check that language, +;; which can be useful for languages without an ispell dictionary. + +;;; Customization: +;; +;; The code that follows is an example of my customization of this +;; package. The first form tells the package to turn on debugging +;; messages to see when we switch dictionaries as we move from place +;; to place. The second tells it not to spell-check the languages +;; "latin" and "ibycus" (an encoding for ancient Greek), since I don't +;; have ispell dictionaries for them; it also tells it to translate +;; the Babel language "french" to the ispell dictionary "francais". +;; The third form defines some language-switching shortcut commands, +;; so that I can more easily say \fr{merci} and \itl{grazie}. The +;; fourth defines some short-cut environments, since \begin{german} is +;; a lot easier to write than \begin{otherlanguage}{german}. The last +;; form defines some shortcut declarations for switching between +;; American and British spelling. +;; +;; (setq flyspell-babel-verbose t) +;; +;; (setq flyspell-babel-to-ispell-alist +;; '(("latin" nil) +;; ("ibycus" nil) +;; ("french" "francais"))) +;; +;; (setq flyspell-babel-command-alist +;; '(("lat" "latin") +;; ("gk" "ibycus") +;; ("fr" "french") +;; ("ger" "german") +;; ("itl" "italian"))) +;; +;; (setq flyspell-babel-environment-alist +;; '(("latin" "latin") +;; ("greek" "ibycus") +;; ("french" "french") +;; ("german" "german") +;; ("italian" "italian"))) +;; +;; (setq flyspell-babel-declaration-alist +;; '(("yank" "american") +;; ("brit" "british"))) +;; +;; Here is the LaTeX code that defines these short-cuts: +;; +;; \usepackage[ibycus,latin,french,german,italian,british,american]{babel} +;; +;; \newcommand{\lat}[1]{\foreignlanguage{latin}{\emph{#1}}} +;; \newenvironment{latin}{\begin{otherlanguage}{latin}}{\end{otherlanguage}} +;; +;; \newcommand{\fr}[1]{\foreignlanguage{french}{\emph{#1}}} +;; \newenvironment{french}{\begin{otherlanguage}{french}}{\end{otherlanguage}} +;; +;; \newcommand{\ger}[1]{\foreignlanguage{german}{\emph{#1}}} +;; \newenvironment{german}{\begin{otherlanguage}{german}}{\end{otherlanguage}} +;; +;; \newcommand{\itl}[1]{\foreignlanguage{italian}{\emph{#1}}} +;; \newenvironment{italian}{\begin{otherlanguage}{italian}}{\end{otherlanguage}} +;; +;; \newcommand{\yank}{\selectlanguage{american}} +;; \newcommand{\brit}{\selectlanguage{british}} + +;;; Bugs: +;; +;; If a word comes to be erroneously highlighted as misspelled because +;; you have recently changed a Babel command, then the normal thing to +;; do is to wait a few seconds until the idle-timer runs the code to +;; re-parse the text. This works, except when the new Babel language +;; is mapped to 'nil, meaning that it shouldn't be spell-checked at +;; all. When this is the case, the spell-checking mechanism is +;; by-passed completely, so the erroneous highlighting will not be +;; removed, since those words will not be re-recognized as "correctly" +;; spelled. The best thing to do in this case is to switch +;; flyspell-mode off and on again, which will remove all flyspell +;; highlighting. + +;;; Changes +;; +;; 3.2 Made flyspell-babel-parse-block non-recursive to avoid blowing +;; max-lisp-eval-depth in long files +;; 3.1 Fixed bug when \usepackage[foo]{babel} was commented out +;; 3.0 Re-factored to use new ispell-multi.el. +;; 2.0 Major re-write. Instead of partially-parsing every time a word +;; is spell-checked, we now cache the language in a text property, +;; and use an idle timer to re-parse in case the language has +;; changed. +;; 1.3 Only use ispell-valid-dictionary-list if it's available +;; 1.2 Removed dependency on AUCTeX and newcomment and fixed bug when +;; disabling flyspell-large-region +;; 1.1 Removed error report when \usepackage{babel} not present +;; 1.0 Initial public release + +(require 'ispell-multi) +(require 'flyspell) + +(defgroup flyspell-babel nil + "Switch flyspell language according to LaTeX babel commands" + :tag "Switch flyspell language according to Babel commands" + :group 'tex + :prefix "flyspell-babel-") + +(defcustom flyspell-babel-to-ispell-alist () + "Maps LaTeX babel language or dialect names to ispell + dictionaries" + :type 'alist + :group 'flyspell-babel) + +(defcustom flyspell-babel-declaration-alist () + "Maps LaTeX language-switching declarations (other than the + built-in babel \\selectlanguage declaration) to babel + languages" + :type 'alist + :group 'flyspell-babel) + +(defcustom flyspell-babel-environment-alist () + "Maps LaTeX language-switching environments (other than the + built-in babel \"otherlanguage\" environment) to babel languages" + :type 'alist + :group 'flyspell-babel) + +(defcustom flyspell-babel-command-alist () + "Maps LaTeX language-switching commands (other than the + built-in babel \\foreignlanguage command) to babel languages" + :type 'alist + :group 'flyspell-babel) + +(defcustom flyspell-babel-verbose nil + "Whether routinely to report changing from one language to another" + :type 'boolean + :group 'flyspell-babel) + +(defcustom flyspell-babel-delay 5 + "Seconds of idleness before current Babel block is re-parsed." + :type 'integer + :group 'flyspell-babel) + + +(defvar flyspell-babel-declaration-alist-all nil) +(defvar flyspell-babel-decl-regexp nil) +(defvar flyspell-babel-environment-alist-all nil) +(defvar flyspell-babel-env-regexp nil) +(defvar flyspell-babel-command-alist-all nil) +(defvar flyspell-babel-com-regexp nil) +(defvar flyspell-babel-decl-env-com-regexp nil) + +(setq flyspell-babel-declaration-alist-all + (append '(("selectlanguage" "selectlanguage")) + flyspell-babel-declaration-alist)) + +(setq flyspell-babel-decl-regexp + (concat "\\\\begin[ \t\n]*{document}" "\\|" + (mapconcat (lambda (pair) (concat "\\\\" (car pair) "[ \t\n{]")) + flyspell-babel-declaration-alist-all "\\|"))) + +(setq flyspell-babel-environment-alist-all + (append '(("otherlanguage" "otherlanguage")) + flyspell-babel-environment-alist)) + +(setq flyspell-babel-env-regexp + (mapconcat (lambda (pair) (concat "\\\\begin{" (car pair) "}")) + flyspell-babel-environment-alist-all "\\|")) + +(setq flyspell-babel-command-alist-all + (append '(("foreignlanguage" "foreignlanguage")) + flyspell-babel-command-alist)) + +(setq flyspell-babel-com-regexp + (mapconcat (lambda (pair) (concat "\\\\" (car pair) "[ \t\n{]")) + flyspell-babel-command-alist-all "\\|")) + +(setq flyspell-babel-decl-env-com-regexp + (mapconcat 'identity (list flyspell-babel-decl-regexp + flyspell-babel-env-regexp + flyspell-babel-com-regexp) "\\|")) + + +(defun flyspell-babel-parse-buffer () + (save-excursion + (goto-char (point-max)) + (flyspell-babel-parse))) + +(defun flyspell-babel-parse () + "Parse backward from point until containing element or bob is +found; then run forward and flag regions found." + (let ((current-position (point)) + beg end lang macro-begin tag-list finished) + (while (and (not finished) + (not (input-pending-p)) + (flyspell-babel-find-previous-macro nil)) + ;; We standardize on having the language switch happening + ;; just *after* regexp-match, since re-search-backward + ;; will fail to match when we are in the middle of a macro. + (setq beg (match-end 0)) + (setq macro-begin (point)) + (if (looking-at flyspell-babel-com-regexp) + (flyspell-babel-check-com) + (if (looking-at flyspell-babel-env-regexp) + (flyspell-babel-check-env) + (if (looking-at flyspell-babel-decl-regexp) + (flyspell-babel-check-decl) + (flyspell-babel-message "internal error 1")))) + (setq end (point)) + (when (< current-position end) + ;; Got it + (setq finished t) + ;; As an optimization, we flag the text after point + ;; as far as the start of the next Babel command. + (goto-char current-position) + (when (and (flyspell-babel-find-next-macro end) + (< current-position (point)) + (< (point) end)) + (setq end (1+ (point))))) + (setq tag-list (cons (list beg end lang) tag-list)) + (goto-char macro-begin)) + ;; Background is default lang + (setq tag-list (cons (list (point-min) current-position "no-command-found") tag-list)) + ;; We now run through in a forward direction + (while tag-list + (apply 'flyspell-babel-flag-region (car tag-list)) + (setq tag-list (cdr tag-list))))) + + + +(defun flyspell-babel-find-previous-macro (end) + (let ((found)) + (while (and (not found) + (re-search-backward flyspell-babel-decl-env-com-regexp end t)) + (setq found (not (flyspell-babel-in-comment-p)))) + found)) + +(defun flyspell-babel-find-next-macro (end) + (let ((found)) + (while (and (not found) + (re-search-forward flyspell-babel-decl-env-com-regexp end t)) + (setq found (not (flyspell-babel-in-comment-p)))) + found)) + +(defun flyspell-babel-check-com () + (if (re-search-forward + "\\=\\\\foreignlanguage[ \t\n]*{\\([^}]+\\)}[ \t\n]*{" nil t) + (setq lang (match-string 1)) + (if (re-search-forward "\\=\\\\\\([^{ \t\n]+\\)[ \t\n]*{" nil t) + (setq lang (cadr + (assoc (match-string 1) + flyspell-babel-command-alist-all))) + (flyspell-babel-message "internal error 2"))) + (backward-char) + (flyspell-babel-forward-sexp)) + +(defun flyspell-babel-check-env () + (let ((env)) + (if (looking-at "\\=\\\\begin{otherlanguage}[ \t\n]*{\\([^}]+\\)}") + (setq env "otherlanguage" lang (match-string 1)) + (if (looking-at "\\=\\\\begin[ \t\n]*{\\([^}]+\\)}") + (setq env (match-string 1) + lang (cadr + (assoc env flyspell-babel-environment-alist-all))) + (flyspell-babel-message "internal error 3"))) + (flyspell-babel-find-matching-end env) +; (backward-char))) + )) + +(defun flyspell-babel-check-decl () + (if (looking-at "\\\\begin[ \t\n]*{document}") + (progn + (if (save-excursion + (re-search-backward + ;; To exclude commented lines, only allow spaces before + "^[ \t\n]*\\\\usepackage.*[[,]\\([^]]+\\)\\]{babel}" nil t)) + (setq lang (match-string 1)) + (setq lang "no-command-found")) + (goto-char (point-max))) + (if (looking-at "\\\\selectlanguage[ \t\n]*{\\([^}]+\\)}") + (setq lang (match-string 1)) + (if (and (looking-at "\\\\\\([^{ \t\n]+\\)") + (cadr (assoc (match-string 1) + flyspell-babel-declaration-alist-all))) + (setq lang + (cadr (assoc (match-string 1) + flyspell-babel-declaration-alist-all))) + (flyspell-babel-message "internal error 4"))) + (unless (bobp) + (backward-char)) + (if (looking-at "{") + (flyspell-babel-forward-sexp) + (goto-char (point-max))))) + +(defun flyspell-babel-flag-region (beg end lang) + (let ((trans (assoc lang flyspell-babel-to-ispell-alist)) + (buffer-modified-before (buffer-modified-p)) + (after-change-functions nil)) + (when trans + ;; We have a translation of a Babel language name to ispell + ;; nomenclature + (setq lang (cadr trans))) + (cond + ((not lang) + ;; A parsed region with a nil dict -- don't spell-check. + (setq lang "void")) + ((equal lang "no-command-found") + (setq lang "default")) + ((and ispell-multi-valid-dictionary-list + (not (member lang ispell-multi-valid-dictionary-list))) + ;; A parsed region with an uninstalled dict + (message "Flyspell-babel warning: no dictionary installed for %s" lang) + (setq lang "void"))) + (put-text-property beg end 'ispell-multi-lang lang) + (set-buffer-modified-p buffer-modified-before))) + + +(defun flyspell-babel-forward-sexp (&optional arg) + "Makes sure to ignore comments when using forward-sexp, and + trap errors for unbalanced braces." + (interactive "p") + (let ((parse-sexp-ignore-comments t)) + (condition-case nil + (forward-sexp arg) + (error (goto-char (point-max)))))) + +(defun flyspell-babel-find-matching-end (env) + "Find end of current environment, or end of file when there is + no matching \end." + (interactive) + (let ((regexp (concat "\\\\\\(begin\\|end\\)[ \t\n]*{" env "}")) + (level 0) + (proceed t)) + (while proceed + (if (re-search-forward regexp nil t) + (let ((match (match-string 1))) + (unless (flyspell-babel-in-comment-p) + (if (string= match "begin") + (setq level (1+ level)) + (if (string= match "end") + (setq level (1- level)) + (flyspell-babel-message "internal error 5"))))) + (goto-char (point-max)) + (setq proceed nil)) + (when (= 0 level) + (setq proceed nil))))) + +(defun flyspell-babel-in-comment-p () + "Are we in a Latex comment? (Stolen from auctex tex.el)" + (save-match-data + (if (or (bolp) + (null comment-start-skip) + (eq (preceding-char) ?\r)) + nil + (save-excursion + (let ((pos (point))) + (re-search-backward "^\\|\r" nil t) + (or (looking-at comment-start-skip) + (re-search-forward comment-start-skip pos t))))))) + +(defun flyspell-babel-message (mess &optional force) + (when (or flyspell-babel-verbose force) + (message "Flyspell-babel -- %s" mess))) + +(defun flyspell-babel-start () + (flyspell-babel-parse-buffer) + (setq ispell-multi-nil-callback 'flyspell-babel-parse) + (make-local-variable 'flyspell-large-region) + (setq flyspell-large-region 'nil) + (flyspell-mode 1) + (setq flyspell-generic-check-word-p 'ispell-multi-verify) + (setq ispell-multi-idler-callback 'flyspell-babel-parse-buffer) + (ispell-multi-idler-setup flyspell-babel-delay) + (ispell-multi-hack-flyspell-modeline)) + +(defun flyspell-babel-stop () +; (ispell-multi-idler-cancel) + (setq flyspell-generic-check-word-p nil) + (ispell-multi-unhack-flyspell-modeline) + (flyspell-mode -1)) + +(define-minor-mode flyspell-babel-mode + "Mode to make flyspell language selection obey LaTeX Babel commands" nil + :group 'flyspell-babel + (if flyspell-babel-mode + (flyspell-babel-start) + (flyspell-babel-stop))) + +(defun flyspell-babel-setup () + (flyspell-babel-mode 1)) + +(provide 'flyspell-babel) + diff --git a/lisp/fullscreen.el b/lisp/fullscreen.el new file mode 100644 index 0000000..f0145d9 --- /dev/null +++ b/lisp/fullscreen.el @@ -0,0 +1,109 @@ +;;; fullscreen.el --- Full screen + +;; Filename: fullscreen.el +;; Description: Full screen +;; Author: Andy Stewart +;; Maintainer: Andy Stewart +;; Copyright (C) 2009, Andy Stewart, all rights reserved. +;; Created: 2009-02-11 21:05:32 +;; Version: 0.1 +;; Last-Updated: 2009-02-11 21:05:32 +;; By: Andy Stewart +;; URL: http://www.emacswiki.org/emacs/download/fullscreen.el +;; Keywords: fullscreen +;; Compatibility: GNU Emacs 23.0.60.1 +;; +;; Features that might be required by this library: +;; +;; +;; + +;;; This file is NOT part of GNU Emacs + +;;; License +;; +;; 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, 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; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. + +;;; Commentary: +;; +;; Full screen. +;; +;; Below are commands you can use: +;; +;; `fullscreen' Full screen. +;; `fullscreen-toggle' Toggle full screen status. +;; + +;;; Installation: +;; +;; Put fullscreen.el to your load-path. +;; The load-path is usually ~/elisp/. +;; It's set in your ~/.emacs like this: +;; (add-to-list 'load-path (expand-file-name "~/elisp")) +;; +;; And the following to your ~/.emacs startup file. +;; +;; (require 'fullscreen) +;; +;; No need more. + +;;; Customize: +;; +;; +;; +;; All of the above can customize by: +;; M-x customize-group RET fullscreen RET +;; + +;;; Change log: +;; +;; 2009/02/11 +;; * First released. +;; + +;;; Acknowledgements: +;; +;; +;; + +;;; TODO +;; +;; +;; + +;;; Require + + +;;; Code: + + +(defun fullscreen () + "Fullscreen." + (interactive) + (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 + ;; if first parameter is '1', can't toggle fullscreen status + '(1 "_NET_WM_STATE_FULLSCREEN" 0))) + +(defun fullscreen-toggle () + "Toggle fullscreen status." + (interactive) + (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 + ;; if first parameter is '2', can toggle fullscreen status + '(2 "_NET_WM_STATE_FULLSCREEN" 0))) + +(provide 'fullscreen) + +;;; fullscreen.el ends here diff --git a/lisp/highlight-80+.el b/lisp/highlight-80+.el new file mode 100644 index 0000000..f80e928 --- /dev/null +++ b/lisp/highlight-80+.el @@ -0,0 +1,107 @@ +;;; highlight-80+.el --- highlight characters beyond column 80 +;; +;; Copyright (C) 2008 Nikolaj Schumacher +;; +;; Author: Nikolaj Schumacher +;; Version: 1.0 +;; Keywords: faces +;; URL: http://nschum.de/src/emacs/highlight-tabs/ +;; Compatibility: GNU Emacs 22.x +;; +;; This file is NOT part of GNU Emacs. +;; +;; 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, see . +;; +;;; Commentary: +;; +;; This mode highlights all characters that cross the 80 character line limit. +;; +;;; Change Log: +;; +;; 2008-08-11 (1.0) +;; Initial release. +;; +;;; Code: + +(defgroup highlight-80+ nil + "Highlight characters beyond column 80." + :group 'faces) + +(defcustom highlight-80+-columns 80 + "*Number of columns to allow in lines." + :group 'highlight-80+ + :type 'integer) + +(defface highlight-80+-line + nil + "*Face for showing lines with over `highlight-80+-columns'." + :group 'highlight-80+-line) + +(defface highlight-80+ + '((((background dark)) (:background "blue")) + (((background light)) (:background "dark gray"))) + "*Face for showing characters beyond column `highlight-80+-columns'." + :group 'highlight-80+-line) + +(defface highlight-80+-first + nil + "*Face for showing the first character beyond `highlight-80+-columns'." + :group 'highlight-80+-line) + +(defconst highlight-80+-keywords + `((highlight-80+-matcher (0 'highlight-80+-line prepend) + (1 'highlight-80+ prepend) + (2 'highlight-80+-first prepend)))) + +(defsubst highlight-80+-format () + (if (< tab-width 2) + "^\\(\\)\\([^\n]\\)\\{80,\\}$" + (concat (format "^\\(?:[^\t\n]\\{%d\\}\\|[^\t\n]\\{,%d\\}\t\\)\\{%d\\}" + tab-width (- tab-width 1) + (/ highlight-80+-columns tab-width)) + (let ((remainder (mod highlight-80+-columns tab-width))) + (when remainder + (format "\\(?:[^\t\n]\\{%d\\}\\|\t\\)" remainder))) + "\\(\\(.\\).*\\)$"))) + +(defvar highlight-80+-last-width 0) +(make-variable-buffer-local 'highlight-80+-last-width) + +(defvar highlight-80+-last-keywords "") +(make-variable-buffer-local 'highlight-80+-last-keywords) + +(defun highlight-80+-matcher (limit) + ;; Update search when `tab-width' has changed. + (unless (equal highlight-80+-last-width tab-width) + (setq highlight-80+-last-keywords (highlight-80+-format) + highlight-80+-last-width tab-width) + ;; The rest of the buffer can't be right, either. + (let ((font-lock-keywords)) + (font-lock-fontify-buffer))) + ;; re-search-forward is C and much faster checking columns ourselves + (re-search-forward highlight-80+-last-keywords nil t)) + +;;;###autoload +(define-minor-mode highlight-80+-mode + "Highlight the portions of lines longer than 80 characters." + nil " 80+" nil + (if highlight-80+-mode + (font-lock-add-keywords nil highlight-80+-keywords t) + (font-lock-remove-keywords nil highlight-80+-keywords) + (kill-local-variable 'highlight-80+-last-keywords) + (kill-local-variable 'highlight-80+-last-width)) + (font-lock-fontify-buffer)) + +(provide 'highlight-80+) +;;; highlight-80+.el ends here diff --git a/lisp/ido.el b/lisp/ido.el new file mode 100644 index 0000000..0ce83d9 --- /dev/null +++ b/lisp/ido.el @@ -0,0 +1,4766 @@ +;;; ido.el --- interactively do things with buffers and files. + +;; Copyright (C) 1996-2011 Free Software Foundation, Inc. + +;; Author: Kim F. Storm +;; Based on: iswitchb by Stephen Eglen +;; Keywords: extensions convenience + +;; 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: + +;; Ido - interactive do - switches between buffers and opens files and +;; directories with a minimum of keystrokes. It is a superset of +;; iswitchb, the interactive buffer switching package by Stephen Eglen. + +;; Interactive substring matching +;; ------------------------------ +;; +;; As you type in a substring, the list of buffers or files currently +;; matching the substring are displayed as you type. The list is +;; ordered so that the most recent buffers or files visited come at +;; the start of the list. +;; +;; The buffer or file at the start of the list will be the one visited +;; when you press RETURN. By typing more of the substring, the list is +;; narrowed down so that gradually the buffer or file you want will be +;; at the top of the list. Alternatively, you can use C-s and C-r (or +;; the right and left arrow keys) to rotate buffer or file names in the +;; list until the one you want is at the top of the list. +;; +;; Completion is also available so that you can see what is common to +;; all of the matching buffers or files as you type. +;; +;; Example: +;; +;; If I have two buffers called "123456" and "123", with "123456" the +;; most recent, when I use ido-switch-buffer, I first of all get +;; presented with the list of all the buffers +;; +;; Buffer: {123456 | 123} +;; +;; If I then press 2: +;; Buffer: 2[3]{123456 | 123} +;; +;; The list in {...} are the matching buffers, most recent first +;; (buffers visible in the current frame are put at the end of the +;; list by default). At any time I can select the item at the head of +;; the list by pressing RET. I can also put the first element at the +;; end of the list by pressing C-s or [right], or bring the last +;; element to the head of the list by pressing C-r or [left]. +;; +;; The item in [...] indicates what can be added to my input by +;; pressing TAB. In this case, I will get "3" added to my input. + +;; So, I press TAB: +;; Buffer: 23{123456 | 123} +;; +;; At this point, I still have two matching buffers. +;; If I want the first buffer in the list, I simply press RET. If I +;; wanted the second in the list, I could press C-s to move it to the +;; top of the list and then RET to select it. +;; +;; However, if I type 4, I only have one match left: +;; Buffer: 234[123456] +;; +;; Since there is only one matching buffer left, it is given in [] and +;; it is shown in the `ido-only-match' face (ForestGreen). I can now +;; press TAB or RET to go to that buffer. +;; +;; If I want to create a new buffer named "234", I press C-j instead of +;; TAB or RET. +;; +;; If instead, I type "a": +;; Buffer: 234a [No match] +;; There are no matching buffers. If I press RET or TAB, I can be +;; prompted to create a new buffer called "234a". +;; +;; Of course, where this function comes in really useful is when you +;; can specify the buffer using only a few keystrokes. In the above +;; example, the quickest way to get to the "123456" file would be +;; just to type 4 and then RET (assuming there isn't any newer buffer +;; with 4 in its name). + +;; Likewise, if you use C-x C-f (ido-find-file), the list of files and +;; directories in the current directory is provided in the same +;; fashion as the buffers above. The files and directories are +;; normally sorted in alphabetical order, but the most recently +;; visited directory is placed first to speed up navigating to +;; directories that you have visited recently. +;; +;; In addition to scrolling through the list using [right] and [left], +;; you can use [up] and [down] to quickly scroll the list to the next +;; or previous subdirectory. +;; +;; To go down into a subdirectory, and continue the file selection on +;; the files in that directory, simply move the directory to the head +;; of the list and hit RET. +;; +;; To go up to the parent directory, delete any partial file name +;; already specified (e.g. using [backspace]) and hit [backspace]. +;; +;; To go to the root directory (on the current drive), enter two +;; slashes. On MS-DOS or Windows, to select the root of another +;; drive, enter X:/ where X is the drive letter. You can also visit +;; files on other hosts using the ange-ftp notations `/host:' and +;; `/user@host:'. See the variable `ido-slow-ftp-hosts' if you want +;; to inhibit the ido substring matching for ftp access. +;; +;; If for some reason you cannot specify the proper file using +;; ido-find-file, you can press C-f to enter the normal find-file. +;; You can also press C-b to drop into ido-switch-buffer. + +;; See the doc string of ido-switch-buffer and ido-find-file for full +;; keybindings and features. +;; (describe-function 'ido-find-file) + +;; Hidden buffers and files +;; ------------------------ +;; +;; Normally, ido does not include hidden buffers (whose name starts +;; with a space) and hidden files and directories (whose name starts +;; with `.') in the list of possible completions. However, if the +;; substring you enter does not match any of the visible buffers or +;; files, ido will automatically look for completions among the hidden +;; buffers or files. +;; +;; You can toggle display of the hidden buffers and files with C-a. + +;; Additional functionality +;; ------------------------ +;; +;; After C-x b, the buffer at the head of the list can be killed by +;; pressing C-k. If the buffer needs saving, you will be queried +;; before the buffer is killed. +;; +;; Likewise, after C-x C-f, you can delete (i.e. physically remove) +;; the file at the head of the list with C-k. You will always be +;; asked for confirmation before the file is deleted. +;; +;; If you enter C-x b to switch to a buffer visiting a given file, and +;; you find that the file you are after is not in any buffer, you can +;; press C-f to immediately drop into ido-find-file. And you can +;; switch back to buffer selection with C-b. + +;; Prefix matching +;; --------------- +;; +;; The standard way of completion with Unix-shells and Emacs is to insert a +;; PREFIX and then hitting TAB (or another completion key). Cause of this +;; behavior has become second nature to a lot of emacs users `ido' offers in +;; addition to the default substring-matching-method (look above) also the +;; prefix-matching-method. The kind of matching is the only difference to +;; the description of the substring-matching above. +;; +;; You can toggle prefix matching with C-p. +;; +;; Example: +;; +;; If you have again two Buffers "123456" and "123" then hitting "2" does +;; not match because "2" is not a PREFIX in any of the buffer-names. + +;; Flexible matching +;; ----------------- +;; +;; If you set ido-enable-flex-matching, ido will do a more flexible +;; matching (unless regexp matching is active) to find possible matches +;; among the available buffer or file names if no matches are found using +;; the normal prefix or substring matching. +;; +;; The flexible matching implies that any item which simply contains all +;; of the entered characters in the specified sequence will match. +;; +;; Example: +;; +;; If you have four files "alpha", "beta", "gamma", and "delta", +;; entering "aa" will match "alpha" and "gamma", while "ea" matches +;; "beta" and "delta". If prefix matching is also active, "aa" only +;; matches "alpha", while "ea" does not match any files. + +;; Regexp matching +;; --------------- +;; +;; There is limited provision for regexp matching within ido, +;; enabled through `ido-enable-regexp' (toggle with C-t). +;; This allows you to type `[ch]$' for example and see all file names +;; ending in `c' or `h'. +;; +;; Note: ido-style completion is inhibited when you enable regexp matching. + + +;; Customization +;; ------------- +;; +;; Customize the `ido' group to change the `ido' functionality. +;; +;; To modify the keybindings, use the ido-setup-hook. For example: +;;(add-hook 'ido-setup-hook 'ido-my-keys) +;; +;;(defun ido-my-keys () +;; "Add my keybindings for ido." +;; (define-key ido-completion-map " " 'ido-next-match) +;; ) + +;; Seeing all the matching buffers or files +;; ---------------------------------------- +;; +;; If you have many matching files, they may not all fit onto one +;; line of the minibuffer. Normally, the minibuffer window will grow +;; to show you more of the matching files (depending on the setting +;; of the variables `resize-mini-windows' and `max-mini-window-height'). +;; If you want ido to behave differently from the default minibuffer +;; resizing behavior, set the variable `ido-max-window-height'. +;; +;; Also, to improve the responsiveness of ido, the maximum number of +;; matching items is limited to 12, but you can increase or removed +;; this limit via the `ido-max-prospects' variable. + +;; To see a full list of all matching buffers in a separate buffer, +;; hit ? or press TAB when there are no further completions to the +;; substring. Repeated TAB presses will scroll you through this +;; separate buffer. + +;; Changing the list of files +;; -------------------------- + +;; By default, the list of current files is most recent first, +;; oldest last, with the exception that the files visible in the +;; current frame are put at the end of the list. A hook exists to +;; allow other functions to order the list. For example, if you add: +;; +;; (add-hook 'ido-make-buffer-list-hook 'ido-summary-buffers-to-end) +;; +;; then all files matching "Summary" are moved to the end of the +;; list. (I find this handy for keeping the INBOX Summary and so on +;; out of the way.) It also moves files matching "output\*$" to the +;; end of the list (these are created by AUCTeX when compiling.) +;; Other functions could be made available which alter the list of +;; matching files (either deleting or rearranging elements.) + +;; Highlighting +;; ------------ + +;; The highlighting of matching items is controlled via ido-use-faces. +;; The faces used are ido-first-match, ido-only-match and +;; ido-subdir. +;; Colouring of the matching item was suggested by +;; Carsten Dominik (dominik@strw.leidenuniv.nl). + +;; Replacement for read-buffer and read-file-name +;; ---------------------------------------------- + +;; ido-read-buffer and ido-read-file-name have been written to be drop +;; in replacements for the normal buffer and file name reading +;; functions `read-buffer' and `read-file-name'. + +;; To use ido for all buffer and file selections in Emacs, customize the +;; variable `ido-everywhere'. + +;; Using ido-like behavior in other lisp packages +;; ----------------------------------------------- + +;; If you don't want to rely on the `ido-everywhere' functionality, +;; ido-read-buffer, ido-read-file-name, and ido-read-directory-name +;; can be used by other packages to read a buffer name, a file name, +;; or a directory name in the `ido' way. + +;;; Acknowledgements + +;; Infinite amounts of gratitude goes to Stephen Eglen +;; who wrote iswitch-buffer mode - from which I ripped off 99% of the code +;; for ido-switch-buffer and found the inspiration for ido-find-file. +;; The ido package would never have existed without his work. + +;; Also thanks to Klaus Berndl, Rohit Namjoshi, Robert Fenk, Alex +;; Schroeder, Bill Benedetto, Stephen Eglen, and many others for bug +;; fixes and improvements. + +;;; History + +;; Since I discovered Stephen Eglen's excellent iswitchb package, I just +;; couldn't live without it, but once being addicted to switching buffers +;; with a minimum of keystrokes, I soon found that opening files in the +;; old-fashioned way was just too slow - so I decided to write a package +;; which could open files with the same speed and ease as iswitchb could +;; switch buffers. + +;; I originally wrote a separate ifindf.el package based on a copy of +;; iswitchb.el, which did for opening files what iswitchb did for +;; switching buffers. Along the way, I corrected a few errors in +;; ifindf which could have found its way back into iswitchb, but since +;; most of the functionality of the two package was practically +;; identical, I decided that the proper thing to do was to merge my +;; ifindf package back into iswitchb. +;; +;; This is basically what ido (interactively do) is all about; but I +;; found it ackward to merge my changes into the "iswitchb-" namespace, +;; so I invented a common "ido-" namespace for the merged packages. +;; +;; This version is based on ido.el version 1.57 released on +;; gnu.emacs.sources adapted for emacs 22.1 to use command remapping +;; and optionally hooking the read-buffer and read-file-name functions. +;; +;; Prefix matching was added by Klaus Berndl based on +;; an idea of Yuji Minejima and his mcomplete-package. + + +;;; Code: + +(defvar recentf-list) + +;;; User Variables +;; +;; These are some things you might want to change. + +(defun ido-fractionp (n) + (and (numberp n) (> n 0.0) (<= n 1.0))) + +(defgroup ido nil + "Switch between files using substrings." + :group 'extensions + :group 'convenience + :version "22.1" + :link '(emacs-commentary-link :tag "Commentary" "ido.el") + :link '(emacs-library-link :tag "Lisp File" "ido.el")) + +;;;###autoload +(defcustom ido-mode nil + "Determines for which functional group \(buffer and files) ido behavior +should be enabled. The following values are possible: +- `buffer': Turn only on ido buffer behavior \(switching, killing, + displaying...) +- `file': Turn only on ido file behavior \(finding, writing, inserting...) +- `both': Turn on ido buffer and file behavior. +- `nil': Turn off any ido switching. + +Setting this variable directly does not take effect; +use either \\[customize] or the function `ido-mode'." + :set #'(lambda (symbol value) + (ido-mode value)) + :initialize 'custom-initialize-default + :require 'ido + :link '(emacs-commentary-link "ido.el") + :set-after '(ido-save-directory-list-file + ;; This will clear ido-unc-hosts-cache, so set it + ;; before loading history file. + ido-unc-hosts) + :type '(choice (const :tag "Turn on only buffer" buffer) + (const :tag "Turn on only file" file) + (const :tag "Turn on both buffer and file" both) + (const :tag "Switch off all" nil)) + :group 'ido) + +(defcustom ido-case-fold case-fold-search + "Non-nil if searching of buffer and file names should ignore case." + :type 'boolean + :group 'ido) + +(defcustom ido-ignore-buffers + '("\\` ") + "List of regexps or functions matching buffer names to ignore. +For example, traditional behavior is not to list buffers whose names begin +with a space, for which the regexp is `\\` '. See the source file for +example functions that filter buffer names." + :type '(repeat (choice regexp function)) + :group 'ido) + +(defcustom ido-ignore-files + '("\\`CVS/" "\\`#" "\\`.#" "\\`\\.\\./" "\\`\\./") + "List of regexps or functions matching file names to ignore. +For example, traditional behavior is not to list files whose names begin +with a #, for which the regexp is `\\`#'. See the source file for +example functions that filter filenames." + :type '(repeat (choice regexp function)) + :group 'ido) + +(defcustom ido-ignore-extensions t + "Non-nil means ignore files in `completion-ignored-extensions' list." + :type 'boolean + :group 'ido) + +(defcustom ido-show-dot-for-dired nil + "Non-nil means to always put . as the first item in file name lists. +This allows the current directory to be opened immediately with `dired'." + :type 'boolean + :group 'ido) + +(defcustom ido-file-extensions-order nil + "List of file extensions specifying preferred order of file selections. +Each element is either a string with `.' as the first char, an empty +string matching files without extension, or t which is the default order +for files with an unlisted file extension." + :type '(repeat (choice string + (const :tag "Default order" t))) + :group 'ido) + +(defcustom ido-ignore-directories + '("\\`CVS/" "\\`\\.\\./" "\\`\\./") + "List of regexps or functions matching sub-directory names to ignore." + :type '(repeat (choice regexp function)) + :group 'ido) + +(defcustom ido-ignore-directories-merge nil + "List of regexps or functions matching directory names to ignore during merge. +Directory names matched by one of the regexps in this list are not inserted +in merged file and directory lists." + :type '(repeat (choice regexp function)) + :group 'ido) + +;; Examples for setting the value of ido-ignore-buffers +;;(defun ido-ignore-c-mode (name) +;; "Ignore all c mode buffers -- example function for ido." +;; (with-current-buffer name +;; (derived-mode-p 'c-mode))) +;; +;;(setq ido-ignore-buffers '("^ " ido-ignore-c-mode)) + +;; Examples for setting the value of ido-ignore-files +;;(setq ido-ignore-files '("^ " "\\.c\\'" "\\.h\\'")) + +(defcustom ido-default-file-method 'raise-frame + "How to visit a new file when using `ido-find-file'. +Possible values: +`selected-window' Show new file in selected window +`other-window' Show new file in another window (same frame) +`display' Display file in another window without selecting to it +`other-frame' Show new file in another frame +`maybe-frame' If a file is visible in another frame, prompt to ask if you + you want to see the file in the same window of the current + frame or in the other frame +`raise-frame' If a file is visible in another frame, raise that + frame; otherwise, visit the file in the same window" + :type '(choice (const :tag "Visit in selected window" selected-window) + (const :tag "Visit in other window" other-window) + (const :tag "Display (no select) in other window" display) + (const :tag "Visit in other frame" other-frame) + (const :tag "Ask to visit in other frame" maybe-frame) + (const :tag "Raise frame if already visited" raise-frame)) + :group 'ido) + +(defcustom ido-default-buffer-method 'raise-frame + "How to switch to new buffer when using `ido-switch-buffer'. +See `ido-default-file-method' for details." + :type '(choice (const :tag "Show in selected window" selected-window) + (const :tag "Show in other window" other-window) + (const :tag "Display (no select) in other window" display) + (const :tag "Show in other frame" other-frame) + (const :tag "Ask to show in other frame" maybe-frame) + (const :tag "Raise frame if already shown" raise-frame)) + :type '(choice (const selected-window) + (const other-window) + (const display) + (const other-frame) + (const maybe-frame) + (const raise-frame)) + :group 'ido) + +(defcustom ido-enable-flex-matching nil + "Non-nil means that `ido' will do flexible string matching. +Flexible matching means that if the entered string does not +match any item, any item containing the entered characters +in the given sequence will match." + :type 'boolean + :group 'ido) + + +(defcustom ido-enable-regexp nil + "Non-nil means that `ido' will do regexp matching. +Value can be toggled within `ido' using `ido-toggle-regexp'." + :type 'boolean + :group 'ido) + +(defcustom ido-enable-prefix nil + "Non-nil means only match if the entered text is a prefix of file name. +This behavior is like the standard Emacs completion. +If nil, match if the entered text is an arbitrary substring. +Value can be toggled within `ido' using `ido-toggle-prefix'." + :type 'boolean + :group 'ido) + +(defcustom ido-enable-dot-prefix nil + "Non-nil means to match leading dot as prefix. +I.e. hidden files and buffers will match only if you type a dot +as first char even if `ido-enable-prefix' is nil." + :type 'boolean + :group 'ido) + +(defcustom ido-confirm-unique-completion nil + "Non-nil means that even a unique completion must be confirmed. +This means that \\[ido-complete] must always be followed by \\[ido-exit-minibuffer] +even when there is only one unique completion." + :type 'boolean + :group 'ido) + +(defcustom ido-cannot-complete-command 'ido-completion-help + "Command run when `ido-complete' can't complete any more. +The most useful values are `ido-completion-help', which pops up a +window with completion alternatives, or `ido-next-match' or +`ido-prev-match', which cycle the buffer list." + :type 'function + :group 'ido) + + +(defcustom ido-record-commands t + "Non-nil means that `ido' will record commands in command history. +Note that the non-ido equivalent command is recorded." + :type 'boolean + :group 'ido) + +(defcustom ido-max-prospects 12 + "Non-zero means that the prospect list will be limited to that number of items. +For a long list of prospects, building the full list for the minibuffer can take a +non-negligible amount of time; setting this variable reduces that time." + :type 'integer + :group 'ido) + +(defcustom ido-max-file-prompt-width 0.35 + "Non-zero means that the prompt string be limited to that number of characters. +If value is a floating point number, it specifies a fraction of the frame width." + :type '(choice + (integer :tag "Characters" :value 20) + (restricted-sexp :tag "Fraction of frame width" + :value 0.35 + :match-alternatives (ido-fractionp))) + :group 'ido) + +(defcustom ido-max-window-height nil + "Non-nil specifies a value to override `max-mini-window-height'." + :type '(choice + (const :tag "Don't override" nil) + (integer :tag "Number of lines" :value 1) + (restricted-sexp + :tag "Fraction of window height" + :value 0.25 + :match-alternatives (ido-fractionp))) + :group 'ido) + +(defcustom ido-enable-last-directory-history t + "Non-nil means that `ido' will remember latest selected directory names. +See `ido-last-directory-list' and `ido-save-directory-list-file'." + :type 'boolean + :group 'ido) + +(defcustom ido-max-work-directory-list 50 + "Maximum number of working directories to record. +This is the list of directories where files have most recently been opened. +See `ido-work-directory-list' and `ido-save-directory-list-file'." + :type 'integer + :group 'ido) + +(defcustom ido-work-directory-list-ignore-regexps nil + "List of regexps matching directories which should not be recorded. +Directory names matched by one of the regexps in this list are not inserted in +the `ido-work-directory-list' list." + :type '(repeat regexp) + :group 'ido) + + +(defcustom ido-use-filename-at-point nil + "Non-nil means that ido shall look for a filename at point. +May use `ffap-guesser' to guess whether text at point is a filename. +If found, use that as the starting point for filename selection." + :type '(choice + (const :tag "Disabled" nil) + (const :tag "Guess filename" guess) + (other :tag "Use literal filename" t)) + :group 'ido) + + +(defcustom ido-use-url-at-point nil + "Non-nil means that ido shall look for a URL at point. +If found, call `find-file-at-point' to visit it." + :type 'boolean + :group 'ido) + + +(defcustom ido-enable-tramp-completion t + "Non-nil means that ido shall perform tramp method and server name completion. +A tramp file name uses the following syntax: /method:user@host:filename." + :type 'boolean + :group 'ido) + +(defcustom ido-record-ftp-work-directories t + "Non-nil means record ftp file names in the work directory list." + :type 'boolean + :group 'ido) + +(defcustom ido-merge-ftp-work-directories nil + "If nil, merging ignores ftp file names in the work directory list." + :type 'boolean + :group 'ido) + +(defcustom ido-cache-ftp-work-directory-time 1.0 + "Maximum time to cache contents of an ftp directory (in hours). +Use C-l in prompt to refresh list. +If zero, ftp directories are not cached." + :type 'number + :group 'ido) + +(defcustom ido-slow-ftp-hosts nil + "List of slow ftp hosts where ido prompting should not be used. +If an ftp host is on this list, ido automatically switches to the non-ido +equivalent function, e.g. `find-file' rather than `ido-find-file'." + :type '(repeat string) + :group 'ido) + +(defcustom ido-slow-ftp-host-regexps nil + "List of regexps matching slow ftp hosts (see `ido-slow-ftp-hosts')." + :type '(repeat regexp) + :group 'ido) + +(defvar ido-unc-hosts-cache t + "Cached value from `ido-unc-hosts' function.") + +(defcustom ido-unc-hosts nil + "List of known UNC host names to complete after initial //. +If value is a function, that function is called to search network for +hosts on first use of UNC path." + :type '(choice (repeat :tag "List of UNC host names" string) + (function-item :tag "Use `NET VIEW'" + :value ido-unc-hosts-net-view) + (function :tag "Your own function")) + :set #'(lambda (symbol value) + (set symbol value) + (setq ido-unc-hosts-cache t)) + :group 'ido) + +(defcustom ido-downcase-unc-hosts t + "Non-nil if UNC host names should be downcased." + :type 'boolean + :group 'ido) + +(defcustom ido-ignore-unc-host-regexps nil + "List of regexps matching UNC hosts to ignore. +Case is ignored if `ido-downcase-unc-hosts' is set." + :type '(repeat regexp) + :group 'ido) + +(defcustom ido-cache-unc-host-shares-time 8.0 + "Maximum time to cache shares of an UNC host (in hours). +Use C-l in prompt to refresh list. +If zero, UNC host shares are not cached." + :type 'number + :group 'ido) + +(defcustom ido-max-work-file-list 10 + "Maximum number of names of recently opened files to record. +This is the list of the file names (sans directory) which have most recently +been opened. See `ido-work-file-list' and `ido-save-directory-list-file'." + :type 'integer + :group 'ido) + +(defcustom ido-work-directory-match-only t + "Non-nil means to skip non-matching directories in the directory history. +When some text is already entered at the `ido-find-file' prompt, using +\\[ido-prev-work-directory] or \\[ido-next-work-directory] will skip directories +without any matching entries." + :type 'boolean + :group 'ido) + +(defcustom ido-auto-merge-work-directories-length 0 + "Automatically switch to merged work directories during file name input. +The value is number of characters to type before switching to merged mode. +If zero, the switch happens when no matches are found in the current directory. +Automatic merging is disabled if the value is negative." + :type 'integer + :group 'ido) + +(defcustom ido-auto-merge-delay-time 0.70 + "Delay in seconds to wait for more input before doing auto merge." + :type 'number + :group 'ido) + +(defcustom ido-auto-merge-inhibit-characters-regexp "[][*?~]" + "Regexp matching characters which should inhibit automatic merging. +When a (partial) file name matches this regexp, merging is inhibited." + :type 'regexp + :group 'ido) + +(defcustom ido-merged-indicator "^" + "The string appended to first choice if it has multiple directory choices." + :type 'string + :group 'ido) + +(defcustom ido-max-dir-file-cache 100 + "Maximum number of working directories to be cached. +This is the size of the cache of `file-name-all-completions' results. +Each cache entry is time stamped with the modification time of the +directory. Some systems, like Windows, have unreliable directory +modification times, so you may choose to disable caching on such +systems, or explicitly refresh the cache contents using the command +`ido-reread-directory' command (C-l) in the minibuffer. +See also `ido-dir-file-cache' and `ido-save-directory-list-file'." + :type 'integer + :group 'ido) + +(defcustom ido-max-directory-size 30000 + "Maximum size (in bytes) for directories to use ido completion. +If you enter a directory with a size larger than this size, ido will +not provide the normal completion. To show the completions, use C-a." + :type '(choice (const :tag "No limit" nil) + (integer :tag "Size in bytes" 30000)) + :group 'ido) + +(defcustom ido-rotate-file-list-default nil + "Non-nil means that `ido' will always rotate file list to get default in front." + :type 'boolean + :group 'ido) + +(defcustom ido-enter-matching-directory 'only + "Additional methods to enter sub-directory of first/only matching item. +If value is 'first, enter first matching sub-directory when typing a slash. +If value is 'only, typing a slash only enters the sub-directory if it is +the only matching item. +If value is t, automatically enter a sub-directory when it is the only +matching item, even without typing a slash." + :type '(choice (const :tag "Never" nil) + (const :tag "Slash enters first directory" first) + (const :tag "Slash enters first and only directory" only) + (other :tag "Always enter unique directory" t)) + :group 'ido) + +(defcustom ido-create-new-buffer 'prompt + "Specify whether a new buffer is created if no buffer matches substring. +Choices are 'always to create new buffers unconditionally, 'prompt to +ask user whether to create buffer, or 'never to never create new buffer." + :type '(choice (const always) + (const prompt) + (const never)) + :group 'ido) + +(defcustom ido-setup-hook nil + "Hook run after the ido variables and keymap have been setup. +The dynamic variable `ido-cur-item' contains the current type of item that +is read by ido; possible values are file, dir, buffer, and list. +Additional keys can be defined in `ido-completion-map'." + :type 'hook + :group 'ido) + +(defcustom ido-separator nil + "String used by ido to separate the alternatives in the minibuffer. +Obsolete. Set 3rd element of `ido-decorations' instead." + :type '(choice string (const nil)) + :group 'ido) + +(defcustom ido-decorations '( "{" "}" " | " " | ..." "[" "]" " [No match]" " [Matched]" " [Not readable]" " [Too big]" " [Confirm]") + "List of strings used by ido to display the alternatives in the minibuffer. +There are 11 elements in this list: +1st and 2nd elements are used as brackets around the prospect list, +3rd element is the separator between prospects (ignored if `ido-separator' is set), +4th element is the string inserted at the end of a truncated list of prospects, +5th and 6th elements are used as brackets around the common match string which +can be completed using TAB, +7th element is the string displayed when there are no matches, and +8th element is displayed if there is a single match (and faces are not used), +9th element is displayed when the current directory is non-readable, +10th element is displayed when directory exceeds `ido-max-directory-size', +11th element is displayed to confirm creating new file or buffer." + :type '(repeat string) + :group 'ido) + +(defcustom ido-use-virtual-buffers nil + "If non-nil, refer to past buffers as well as existing ones. +Essentially it works as follows: Say you are visiting a file and +the buffer gets cleaned up by mignight.el. Later, you want to +switch to that buffer, but find it's no longer open. With +virtual buffers enabled, the buffer name stays in the buffer +list (using the `ido-virtual' face, and always at the end), and if +you select it, it opens the file back up again. This allows you +to think less about whether recently opened files are still open +or not. Most of the time you can quit Emacs, restart, and then +switch to a file buffer that was previously open as if it still +were. + This feature relies upon the `recentf' package, which will be +enabled if this variable is configured to a non-nil value." + :version "24.1" + :type 'boolean + :group 'ido) + +(defcustom ido-use-faces t + "Non-nil means use ido faces to highlighting first match, only match and +subdirs in the alternatives." + :type 'boolean + :group 'ido) + +(defface ido-first-match '((t (:bold t))) + "Face used by ido for highlighting first match." + :group 'ido) + +(defface ido-only-match '((((class color)) + (:foreground "ForestGreen")) + (t (:italic t))) + "Face used by ido for highlighting only match." + :group 'ido) + +(defface ido-subdir '((((min-colors 88) (class color)) + (:foreground "red1")) + (((class color)) + (:foreground "red")) + (t (:underline t))) + "Face used by ido for highlighting subdirs in the alternatives." + :group 'ido) + +(defface ido-virtual '((t (:inherit font-lock-builtin-face))) + "Face used by ido for matching virtual buffer names." + :version "24.1" + :group 'ido) + +(defface ido-indicator '((((min-colors 88) (class color)) + (:foreground "yellow1" + :background "red1" + :width condensed)) + (((class color)) + (:foreground "yellow" + :background "red" + :width condensed)) + (t (:inverse-video t))) + "Face used by ido for highlighting its indicators." + :group 'ido) + +(defface ido-incomplete-regexp + '((t + (:inherit font-lock-warning-face))) + "Ido face for indicating incomplete regexps." + :group 'ido) + +(defcustom ido-make-file-list-hook nil + "List of functions to run when the list of matching files is created. +Each function on the list may modify the dynamically bound variable +`ido-temp-list' which contains the current list of matching files." + :type 'hook + :group 'ido) + +(defcustom ido-make-dir-list-hook nil + "List of functions to run when the list of matching directories is created. +Each function on the list may modify the dynamically bound variable +`ido-temp-list' which contains the current list of matching directories." + :type 'hook + :group 'ido) + +(defcustom ido-make-buffer-list-hook nil + "List of functions to run when the list of matching buffers is created. +Each function on the list may modify the dynamically bound variable +`ido-temp-list' which contains the current list of matching buffer names." + :type 'hook + :group 'ido) + +(defcustom ido-rewrite-file-prompt-functions nil + "List of functions to run when the find-file prompt is created. +Each function on the list may modify the following dynamically bound +variables: + dirname - the (abbreviated) directory name + to be modified by the hook functions + max-width - the max width of the resulting dirname; nil means no limit + prompt - the basic prompt (e.g. \"Find File: \") + literal - the string shown if doing \"literal\" find; set to nil to omit + vc-off - the string shown if version control is inhibited; set to nil to omit + prefix - either nil or a fixed prefix for the dirname + +The following variables are available, but should not be changed: + `ido-current-directory' - the unabbreviated directory name + item - equals `file' or `dir' depending on the current mode." + :type 'hook + :group 'ido) + +(defvar ido-rewrite-file-prompt-rules nil + "*Alist of rewriting rules for directory names in ido prompts. +A list of elements of the form (FROM . TO) or (FROM . FUNC), each +meaning to rewrite the directory name if matched by FROM by either +substituting the matched string by TO or calling the function FUNC +with the current directory name as its only argument and using the +return value as the new directory name. In addition, each FUNC may +also modify the dynamic variables described for the variable +`ido-rewrite-file-prompt-functions'.") + +(defcustom ido-completion-buffer "*Ido Completions*" + "Name of completion buffer used by ido. +Set to nil to disable completion buffers popping up." + :type 'string + :group 'ido) + +(defcustom ido-completion-buffer-all-completions nil + "Non-nil means to show all completions in completion buffer. +Otherwise, only the current list of matches is shown." + :type 'boolean + :group 'ido) + +(defvar ido-all-frames 'visible + "*Argument to pass to `walk-windows' when finding visible files. +See documentation of `walk-windows' for useful values.") + +(defcustom ido-minibuffer-setup-hook nil + "Ido-specific customization of minibuffer setup. + +This hook is run during minibuffer setup if `ido' is active. +It is intended for use in customizing ido for interoperation +with other packages. For instance: + + \(add-hook 'ido-minibuffer-setup-hook + \(function + \(lambda () + \(make-local-variable 'max-mini-window-height) + \(setq max-mini-window-height 3)))) + +will constrain Emacs to a maximum minibuffer height of 3 lines when +ido is running. Copied from `icomplete-minibuffer-setup-hook'." + :type 'hook + :group 'ido) + +(defcustom ido-save-directory-list-file (convert-standard-filename "~/.ido.last") + "File in which the ido state is saved between invocations. +Variables stored are: `ido-last-directory-list', `ido-work-directory-list', +`ido-work-file-list', and `ido-dir-file-cache'. +Must be set before enabling ido mode." + :type 'string + :group 'ido) + +(defcustom ido-read-file-name-as-directory-commands '() + "List of commands which uses `read-file-name' to read a directory name. +When `ido-everywhere' is non-nil, the commands in this list will read +the directory using `ido-read-directory-name'." + :type '(repeat symbol) + :group 'ido) + +(defcustom ido-read-file-name-non-ido '() + "List of commands which shall not read file names the ido way. +When `ido-everywhere' is non-nil, the commands in this list will read +the file name using normal `read-file-name' style." + :type '(repeat symbol) + :group 'ido) + +(defcustom ido-before-fallback-functions '() + "List of functions to call before calling a fallback command. +The fallback command is passed as an argument to the functions." + :type 'hook + :group 'ido) + +;;; Internal Variables + +;; Persistent variables + +(defvar ido-completion-map nil + "Currently active keymap for ido commands.") + +(defvar ido-common-completion-map nil + "Keymap for all ido commands.") + +(defvar ido-file-completion-map nil + "Keymap for ido file commands.") + +(defvar ido-file-dir-completion-map nil + "Keymap for ido file and directory commands.") + +(defvar ido-buffer-completion-map nil + "Keymap for ido buffer commands.") + +(defvar ido-file-history nil + "History of files selected using `ido-find-file'.") + +(defvar ido-buffer-history nil + "History of buffers selected using `ido-switch-buffer'.") + +(defvar ido-last-directory-list nil + "List of last selected directory names. +See `ido-enable-last-directory-history' for details.") + +(defvar ido-work-directory-list nil + "List of actual working directory names. +The current directory is inserted at the front of this list whenever a +file is opened with `ido-find-file' and family.") + +(defvar ido-work-file-list nil + "List of actual work file names. +Opening a file with `ido-find-file' and similar functions +inserts the current file name (relative to its containing directory) +at the front of this list.") + +(defvar ido-dir-file-cache nil + "List of `file-name-all-completions' results. +Each element in the list is of the form (DIR (MTIME) FILE...).") + +(defvar ido-ignore-item-temp-list nil + "List of items to ignore in current ido invocation. +Intended to be let-bound by functions which call ido repeatedly. +Should never be set permanently.") + +;; Temporary storage + +(defvar ido-eoinput 1 + "Point where minibuffer input ends and completion info begins. +Copied from `icomplete-eoinput'.") +(make-variable-buffer-local 'ido-eoinput) + +(defvar ido-common-match-string nil + "Stores the string that is common to all matching files.") + +(defvar ido-rescan nil + "Non-nil means we need to regenerate the list of matching items.") + +(defvar ido-rotate nil + "Non-nil means we are rotating list of matches.") + +(defvar ido-text nil + "Stores the users string as it is typed in.") + +(defvar ido-text-init nil + "The initial string for the users string it is typed in.") + +(defvar ido-input-stack nil + "Stores the users strings when user hits M-b/M-f.") + +(defvar ido-matches nil + "List of files currently matching `ido-text'.") + +(defvar ido-report-no-match t + "Report [No Match] when no completions matches `ido-text'.") + +(defvar ido-exit nil + "Flag to monitor how `ido-find-file' exits. +If equal to `takeprompt', we use the prompt as the file name to be +selected.") + +(defvar ido-current-directory nil + "Current directory for `ido-find-file'.") + +(defvar ido-auto-merge-timer nil + "Delay timer for auto merge.") + +(defvar ido-use-mycompletion-depth 0 + "Non-nil means use `ido' completion feedback. +Is set by ido functions to the current `minibuffer-depth', +so that it doesn't interfere with other minibuffer usage.") + +(defvar ido-incomplete-regexp nil + "Non-nil if an incomplete regexp is entered.") + +(defvar ido-initial-position nil + "Non-nil means to explicitly cursor on entry to minibuffer. +Value is an integer which is number of chars to right of prompt.") + +(defvar ido-virtual-buffers nil + "List of virtual buffers, that is, past visited files. +This is a copy of `recentf-list', pared down and with faces applied. +Only used if `ido-use-virtual-buffers' is non-nil.") + +;;; Variables with dynamic bindings. +;;; Declared here to keep the byte compiler quiet. + +;; Stores the current ido item type ('file, 'dir, 'buffer, or 'list). +(defvar ido-cur-item) + +;;; Stores the current default item +(defvar ido-default-item) + +;; Stores the current list of items that will be searched through. +;; The list is ordered, so that the most interesting item comes first, +;; although by default, the files visible in the current frame are put +;; at the end of the list. Created by `ido-make-item-list'. +(defvar ido-cur-list) + +;; Stores the choice list for ido-completing-read +(defvar ido-choice-list) + +;; Stores the list of items which are ignored when building +;; `ido-cur-list'. It is in no specific order. +(defvar ido-ignored-list) + +;; Remember if current directory is non-readable (so we cannot do completion). +(defvar ido-directory-nonreadable) + +;; Remember if current directory is 'huge' (so we don't want to do completion). +(defvar ido-directory-too-big) + +;; Keep current item list if non-nil. +(defvar ido-keep-item-list) + +;; Process ido-ignore-* lists. +(defvar ido-process-ignore-lists) + +;; Don't process ido-ignore- lists once. +(defvar ido-process-ignore-lists-inhibit) + +;; Buffer from which ido was entered. +(defvar ido-entry-buffer) + +;; Non-nil if matching file must be selected. +(defvar ido-require-match) + +;; Non-nil if we should add [confirm] to prompt +(defvar ido-show-confirm-message) + +;; Stores a temporary version of the file list being created. +(defvar ido-temp-list) + +;; Non-nil if default list element should be rotated into place. +(defvar ido-rotate-temp) + +;; Stores current index in ido-work-directory-list. +(defvar ido-work-directory-index) + +;; Stores current index in ido-work-file-list. +(defvar ido-work-file-index) + +;; Set when merged work directory list is in use. +(defvar ido-use-merged-list) + +;; Set when merged work directory list not yet built. +(defvar ido-try-merged-list) + +;; Saved state prior to last work directory merge. +;; Value is a list (ido-text dir cur-list ignored-list matches). +(defvar ido-pre-merge-state) + +;; Original value of vc-handled-backends for use in ido-toggle-vc. +(defvar ido-saved-vc-hb) + +;; Stores temporary state of literal find file. +(defvar ido-find-literal) + +;; Set to 'ignore to inhibit switching between find-file/switch-buffer. +(defvar ido-context-switch-command) + +;;; FUNCTIONS + +(defun ido-active (&optional merge) + (if merge + ido-use-merged-list + (and (boundp 'ido-completing-read) + (or (featurep 'xemacs) + (= ido-use-mycompletion-depth (minibuffer-depth)))))) + +(defvar ido-trace-enable nil) + +(defun ido-trace (p &optional s retval) + (if ido-trace-enable + (let ((b (get-buffer-create " *IDO Trace*")) + (deactivate-mark deactivate-mark)) + (save-excursion + (save-restriction + (set-buffer b) + (insert p ": " (if (stringp s) s (format "%S" s)) "\n"))))) + retval) + +(defun ido-toggle-trace (arg) + (interactive "P") + (setq ido-trace-enable (or arg (not ido-trace-enable))) + (if ido-trace-enable + (message "IDO trace on")) + (let ((b (get-buffer " *IDO Trace*"))) + (if b + (if ido-trace-enable + (kill-buffer b) + (pop-to-buffer b t t) + (setq truncate-lines t))))) + +(defun ido-local-file-exists-p (file) + "Tell if FILE exists locally." + (let (file-name-handler-alist) + (file-exists-p file))) + +(defun ido-unc-hosts (&optional query) + "Return list of UNC host names." + (let ((hosts + (cond + ((listp ido-unc-hosts) + ido-unc-hosts) ;; static list or nil + ((listp ido-unc-hosts-cache) + ido-unc-hosts-cache) ;; result of net search + ((and query (fboundp ido-unc-hosts)) + (message (propertize "Searching for UNC hosts..." 'face 'highlight)) + (setq ido-unc-hosts-cache (funcall ido-unc-hosts)) + (message nil) + ido-unc-hosts-cache) + (query + (setq ido-unc-hosts-cache nil)) + (t (fboundp ido-unc-hosts))))) + (when query + (let ((case-fold-search ido-downcase-unc-hosts) + res host re-list re) + (while hosts + (setq host (car hosts) + hosts (cdr hosts) + re-list (and ido-process-ignore-lists + ido-ignore-unc-host-regexps)) + (while re-list + (setq re (car re-list) + re-list (cdr re-list)) + (if (string-match re host) + (setq re-list nil + host nil))) + (when host + (when ido-downcase-unc-hosts + (setq host (downcase host))) + (setq res (cons host res)))) + (setq hosts (sort res #'string<)))) + hosts)) + +(defun ido-unc-hosts-net-view () + "Query network for list of UNC host names using `NET VIEW'." + (let (hosts) + (with-temp-buffer + (shell-command "net view" t) + (goto-char (point-min)) + (while (re-search-forward "^\\\\\\\\\\([[:graph:]]+\\)" nil t) + (setq hosts (cons (match-string 1) hosts)))) + hosts)) + +(defun ido-is-tramp-root (&optional dir) + (and ido-enable-tramp-completion + (string-match "\\`/[^/]+[@:]\\'" + (or dir ido-current-directory)))) + +(defun ido-is-unc-root (&optional dir) + (and (ido-unc-hosts) + (string-equal "//" + (or dir ido-current-directory)))) + +(defun ido-is-unc-host (&optional dir) + (and (ido-unc-hosts) + (string-match "\\`//[^/]+/\\'" + (or dir ido-current-directory)))) + +(defun ido-is-root-directory (&optional dir) + (setq dir (or dir ido-current-directory)) + (or + (string-equal "/" dir) + (and (memq system-type '(windows-nt ms-dos)) + (string-match "\\`[a-zA-Z]:[/\\]\\'" dir)) + (if ido-enable-tramp-completion + (ido-is-tramp-root dir) + (string-match "\\`/[^:/][^:/]+:\\'" dir)))) + +(defun ido-is-ftp-directory (&optional dir) + (string-match + (if ido-enable-tramp-completion + "\\`/[^/:][^/:]+:" ;; like tramp-file-name-regexp-unified, but doesn't match single drive letters + "\\`/[^/:][^/:]+:/") + (or dir ido-current-directory))) + +(defun ido-is-slow-ftp-host (&optional dir) + (and (or ido-slow-ftp-hosts ido-slow-ftp-host-regexps) + (setq dir (or dir ido-current-directory)) + ;; (featurep 'ange-ftp) + ;; (ange-ftp-ftp-name dir) + (string-match + (if ido-enable-tramp-completion + "\\`/\\([^/]+[@:]\\)*\\([^@/:][^@/:]+\\):" + "\\`/\\([^/:]*@\\)?\\([^@/:][^@/:]+\\):/") + dir) + (let ((host (substring dir (match-beginning 2) (match-end 2)))) + (or (member host ido-slow-ftp-hosts) + (let ((re ido-slow-ftp-host-regexps)) + (while (and re (not (string-match (car re) host))) + (setq re (cdr re))) + re))))) + +(defun ido-time-stamp (&optional time) + ;; Time is a floating point number (fractions of 1 hour) + (setq time (or time (current-time))) + (/ (+ (* (car time) 65536.0) (car (cdr time))) 3600.0)) + +(defun ido-cache-ftp-valid (&optional time) + (and (numberp ido-cache-ftp-work-directory-time) + (> ido-cache-ftp-work-directory-time 0) + (or (not time) + (< (- (ido-time-stamp) time) ido-cache-ftp-work-directory-time)))) + +(defun ido-cache-unc-valid (&optional time) + (and (numberp ido-cache-unc-host-shares-time) + (> ido-cache-unc-host-shares-time 0) + (or (not time) + (< (- (ido-time-stamp) time) ido-cache-unc-host-shares-time)))) + +(defun ido-may-cache-directory (&optional dir) + (setq dir (or dir ido-current-directory)) + (cond + ((and (ido-is-root-directory dir) + (or ido-enable-tramp-completion + (memq system-type '(windows-nt ms-dos)))) + nil) + ((ido-is-unc-host dir) + (ido-cache-unc-valid)) + ((ido-is-ftp-directory dir) + (ido-cache-ftp-valid)) + ((ido-directory-too-big-p dir) + nil) + (t t))) + +(defun ido-pp (list &optional sep) + (let ((print-level nil) (eval-expression-print-level nil) + (print-length nil) (eval-expression-print-length nil)) + (insert "\n;; ----- " (symbol-name list) " -----\n(\n ") + (setq list (symbol-value list)) + (while list + (let* ((elt (car list)) + (s (if (consp elt) (car elt) elt))) + (if (and (stringp s) (= (length s) 0)) + (setq s nil)) + (if s + (prin1 elt (current-buffer))) + (if (and (setq list (cdr list)) s) + (insert (or sep "\n "))))) + (insert "\n)\n"))) + +(defun ido-save-history () + "Save ido history and cache information between sessions." + (interactive) + (when (and ido-last-directory-list ido-save-directory-list-file) + (let ((buf (get-buffer-create " *ido session*")) + (version-control 'never)) + (unwind-protect + (with-current-buffer buf + (erase-buffer) + (insert ";;; -*- coding: utf-8 -*-\n") + (setq buffer-file-coding-system 'utf-8) + (ido-pp 'ido-last-directory-list) + (ido-pp 'ido-work-directory-list) + (ido-pp 'ido-work-file-list) + (ido-pp 'ido-dir-file-cache "\n\n ") + (if (listp ido-unc-hosts-cache) + (ido-pp 'ido-unc-hosts-cache) + (insert "\n;; ----- ido-unc-hosts-cache -----\nt\n")) + (write-file ido-save-directory-list-file nil)) + (kill-buffer buf))))) + +(defun ido-load-history (&optional arg) + "Load ido history and cache information from previous session. +With prefix argument, reload history unconditionally." + (interactive "P") + (if (or arg (and ido-save-directory-list-file (not ido-last-directory-list))) + (let ((file (expand-file-name ido-save-directory-list-file)) + buf) + (when (file-readable-p file) + (setq buf (get-buffer-create " *ido session*")) + (unwind-protect + (with-current-buffer buf + (erase-buffer) + (insert-file-contents file) + (condition-case nil + (setq ido-last-directory-list (read (current-buffer)) + ido-work-directory-list (read (current-buffer)) + ido-work-file-list (read (current-buffer)) + ido-dir-file-cache (read (current-buffer)) + ido-unc-hosts-cache (read (current-buffer))) + (error nil))) + (kill-buffer buf))))) + (ido-wash-history)) + +(defun ido-wash-history () + "Clean-up ido history and cache information. +Removes badly formatted data and ignored directories." + (interactive) + ;; Check format of each of our lists, discard bogus elements + (setq ido-last-directory-list + (and (listp ido-last-directory-list) + (let ((l ido-last-directory-list) r) + (while l + (if (and (consp (car l)) + (stringp (car (car l))) + (stringp (cdr (car l)))) + (setq r (cons (car l) r))) + (setq l (cdr l))) + (nreverse r)))) + (setq ido-work-directory-list + (and (listp ido-work-directory-list) + (let ((l ido-work-directory-list) r) + (while l + (if (and (stringp (car l)) + (or ido-record-ftp-work-directories + (not (ido-is-ftp-directory (car l))))) + (setq r (cons (car l) r))) + (setq l (cdr l))) + (nreverse r)))) + (setq ido-work-file-list + (and (listp ido-work-file-list) + (let ((l ido-work-file-list) r) + (while l + (if (stringp (car l)) + (setq r (cons (car l) r))) + (setq l (cdr l))) + (nreverse r)))) + (setq ido-dir-file-cache + (and (listp ido-dir-file-cache) + (let ((l ido-dir-file-cache) r) + (while l + (if (and (listp (car l)) + (> (length (car l)) 2) + (let ((dir (car (car l))) + (time (car (cdr (car l)))) + (files (cdr (cdr (car l))))) + (and + (stringp dir) + (consp time) + (cond + ((integerp (car time)) + (and (/= (car time) 0) + (integerp (car (cdr time))) + (/= (car (cdr time)) 0) + (ido-may-cache-directory dir))) + ((eq (car time) 'ftp) + (and (numberp (cdr time)) + (ido-is-ftp-directory dir) + (ido-cache-ftp-valid (cdr time)))) + ((eq (car time) 'unc) + (and (numberp (cdr time)) + (ido-is-unc-host dir) + (ido-cache-unc-valid (cdr time)))) + (t nil)) + (let ((s files) (ok t)) + (while s + (if (stringp (car s)) + (setq s (cdr s)) + (setq s nil ok nil))) + ok)))) + (setq r (cons (car l) r))) + (setq l (cdr l))) + (nreverse r)))) + + ;; Remove ignored directories from work directory list + ;; according to ido-work-directory-list-ignore-regexps + (if ido-work-directory-list + (let ((dirs (reverse ido-work-directory-list))) + (setq ido-work-directory-list nil) + (while dirs + (ido-record-work-directory (car dirs)) + (setq dirs (cdr dirs))))) + ;; Get rid of text properties + (let ((l ido-last-directory-list) e) + (while l + (setq e (car l) l (cdr l)) + (set-text-properties 0 (length (car e)) nil (car e)) + (set-text-properties 0 (length (cdr e)) nil (cdr e)))) + (let ((l ido-work-directory-list) e) + (while l + (setq e (car l) l (cdr l)) + (set-text-properties 0 (length e) nil e))) + (let ((l ido-work-file-list) e) + (while l + (setq e (car l) l (cdr l)) + (set-text-properties 0 (length e) nil e))) + (let ((l ido-dir-file-cache) e d) + (while l + (setq e (car l) l (cdr l)) + (if (listp e) + (while e + (setq d (car e) e (cdr e)) + (if (not (consp d)) + (set-text-properties 0 (length d) nil d))))))) + + +(defun ido-kill-emacs-hook () + ;; ido kill emacs hook + (ido-save-history)) + +(defun ido-common-initialization () + (ido-init-completion-maps) + (add-hook 'minibuffer-setup-hook 'ido-minibuffer-setup) + (add-hook 'choose-completion-string-functions 'ido-choose-completion-string)) + +(define-minor-mode ido-everywhere + "Toggle using ido-mode everywhere file and directory names are read. +With ARG, turn ido-mode on if arg is positive, off otherwise." + :global t + :group 'ido + (when (get 'ido-everywhere 'file) + (setq read-file-name-function (car (get 'ido-everywhere 'file))) + (put 'ido-everywhere 'file nil)) + (when (get 'ido-everywhere 'buffer) + (setq read-buffer-function (car (get 'ido-everywhere 'buffer))) + (put 'ido-everywhere 'buffer nil)) + (when ido-everywhere + (when (memq ido-mode '(both file)) + (put 'ido-everywhere 'file (cons read-file-name-function nil)) + (setq read-file-name-function 'ido-read-file-name)) + (when (memq ido-mode '(both buffer)) + (put 'ido-everywhere 'buffer (cons read-buffer-function nil)) + (setq read-buffer-function 'ido-read-buffer)))) + +(defvar ido-minor-mode-map-entry nil) + +;;;###autoload +(defun ido-mode (&optional arg) + "Toggle ido mode on or off. +With ARG, turn ido-mode on if arg is positive, off otherwise. +Turning on ido-mode will remap (via a minor-mode keymap) the default +keybindings for the `find-file' and `switch-to-buffer' families of +commands to the ido versions of these functions. +However, if ARG arg equals 'files, remap only commands for files, or +if it equals 'buffers, remap only commands for buffer switching. +This function also adds a hook to the minibuffer." + (interactive "P") + (setq ido-mode + (cond + ((null arg) (if ido-mode nil 'both)) + ((eq arg t) 'both) + ((eq arg 'files) 'file) + ((eq arg 'buffers) 'buffer) + ((memq arg '(file buffer both)) arg) + ((> (prefix-numeric-value arg) 0) 'both) + (t nil))) + + (ido-everywhere (if ido-everywhere 1 -1)) + + (when ido-mode + (ido-common-initialization) + (ido-load-history) + + (add-hook 'kill-emacs-hook 'ido-kill-emacs-hook) + + (let ((map (make-sparse-keymap))) + (when (memq ido-mode '(file both)) + (define-key map [remap find-file] 'ido-find-file) + (define-key map [remap find-file-read-only] 'ido-find-file-read-only) + (define-key map [remap find-alternate-file] 'ido-find-alternate-file) + (define-key map [remap write-file] 'ido-write-file) + (define-key map [remap insert-file] 'ido-insert-file) + (define-key map [remap list-directory] 'ido-list-directory) + (define-key map [remap dired] 'ido-dired) + (define-key map [remap find-file-other-window] + 'ido-find-file-other-window) + (define-key map [remap find-file-read-only-other-window] + 'ido-find-file-read-only-other-window) + (define-key map [remap find-file-other-frame] + 'ido-find-file-other-frame) + (define-key map [remap find-file-read-only-other-frame] + 'ido-find-file-read-only-other-frame)) + + (when (memq ido-mode '(buffer both)) + (define-key map [remap switch-to-buffer] 'ido-switch-buffer) + (define-key map [remap switch-to-buffer-other-window] + 'ido-switch-buffer-other-window) + (define-key map [remap switch-to-buffer-other-frame] + 'ido-switch-buffer-other-frame) + (define-key map [remap insert-buffer] 'ido-insert-buffer) + (define-key map [remap kill-buffer] 'ido-kill-buffer) + (define-key map [remap display-buffer] 'ido-display-buffer)) + + (if ido-minor-mode-map-entry + (setcdr ido-minor-mode-map-entry map) + (setq ido-minor-mode-map-entry (cons 'ido-mode map)) + (add-to-list 'minor-mode-map-alist ido-minor-mode-map-entry)))) + + (message "Ido mode %s" (if ido-mode "enabled" "disabled"))) + + +;;; IDO KEYMAP +(defun ido-init-completion-maps () + "Set up the completion keymaps used by `ido'." + + ;; Common map + (let ((map (make-sparse-keymap))) + (define-key map "\C-a" 'ido-toggle-ignore) + (define-key map "\C-c" 'ido-toggle-case) + (define-key map "\C-e" 'ido-edit-input) + (define-key map "\t" 'ido-complete) + (define-key map " " 'ido-complete-space) + (define-key map "\C-j" 'ido-select-text) + (define-key map "\C-m" 'ido-exit-minibuffer) + (define-key map "\C-p" 'ido-toggle-prefix) + (define-key map "\C-r" 'ido-prev-match) + (define-key map "\C-s" 'ido-next-match) + (define-key map "\C-t" 'ido-toggle-regexp) + (define-key map "\C-z" 'ido-undo-merge-work-directory) + (define-key map [(control ?\s)] 'ido-restrict-to-matches) + (define-key map [(meta ?\s)] 'ido-take-first-match) + (define-key map [(control ?@)] 'ido-restrict-to-matches) + (define-key map [right] 'ido-next-match) + (define-key map [left] 'ido-prev-match) + (define-key map "?" 'ido-completion-help) + ;; Magic commands. + (define-key map "\C-b" 'ido-magic-backward-char) + (define-key map "\C-f" 'ido-magic-forward-char) + (define-key map "\C-d" 'ido-magic-delete-char) + (set-keymap-parent map minibuffer-local-map) + (setq ido-common-completion-map map)) + + ;; File and directory map + (let ((map (make-sparse-keymap))) + (define-key map "\C-x\C-b" 'ido-enter-switch-buffer) + (define-key map "\C-x\C-f" 'ido-fallback-command) + (define-key map "\C-x\C-d" 'ido-enter-dired) + (define-key map [down] 'ido-next-match-dir) + (define-key map [up] 'ido-prev-match-dir) + (define-key map [(meta up)] 'ido-prev-work-directory) + (define-key map [(meta down)] 'ido-next-work-directory) + (define-key map [backspace] 'ido-delete-backward-updir) + (define-key map "\d" 'ido-delete-backward-updir) + (define-key map [remap delete-backward-char] 'ido-delete-backward-updir) ; BS + (define-key map [remap backward-kill-word] 'ido-delete-backward-word-updir) ; M-DEL + + (define-key map [(control backspace)] 'ido-up-directory) + (define-key map "\C-l" 'ido-reread-directory) + (define-key map [(meta ?d)] 'ido-wide-find-dir-or-delete-dir) + (define-key map [(meta ?b)] 'ido-push-dir) + (define-key map [(meta ?v)] 'ido-push-dir-first) + (define-key map [(meta ?f)] 'ido-wide-find-file-or-pop-dir) + (define-key map [(meta ?k)] 'ido-forget-work-directory) + (define-key map [(meta ?m)] 'ido-make-directory) + (define-key map [(meta ?n)] 'ido-next-work-directory) + (define-key map [(meta ?o)] 'ido-prev-work-file) + (define-key map [(meta control ?o)] 'ido-next-work-file) + (define-key map [(meta ?p)] 'ido-prev-work-directory) + (define-key map [(meta ?s)] 'ido-merge-work-directories) + (set-keymap-parent map ido-common-completion-map) + (setq ido-file-dir-completion-map map)) + + ;; File only map + (let ((map (make-sparse-keymap))) + (define-key map "\C-k" 'ido-delete-file-at-head) + (define-key map "\C-o" 'ido-copy-current-word) + (define-key map "\C-w" 'ido-copy-current-file-name) + (define-key map [(meta ?l)] 'ido-toggle-literal) + (set-keymap-parent map ido-file-dir-completion-map) + (setq ido-file-completion-map map)) + + ;; Buffer map + (let ((map (make-sparse-keymap))) + (define-key map "\C-x\C-f" 'ido-enter-find-file) + (define-key map "\C-x\C-b" 'ido-fallback-command) + (define-key map "\C-k" 'ido-kill-buffer-at-head) + (define-key map "\C-o" 'ido-toggle-virtual-buffers) + (set-keymap-parent map ido-common-completion-map) + (setq ido-buffer-completion-map map))) + + +(defun ido-setup-completion-map () + "Set up the keymap for `ido'." + + ;; generated every time so that it can inherit new functions. + (let ((map (make-sparse-keymap)) + (viper-p (if (boundp 'viper-mode) viper-mode))) + + (when viper-p + (define-key map [remap viper-intercept-ESC-key] 'ignore)) + + (cond + ((memq ido-cur-item '(file dir)) + (when ido-context-switch-command + (define-key map "\C-x\C-b" ido-context-switch-command) + (define-key map "\C-x\C-d" 'ignore)) + (when viper-p + (define-key map [remap viper-backward-char] 'ido-delete-backward-updir) + (define-key map [remap viper-del-backward-char-in-insert] 'ido-delete-backward-updir) + (define-key map [remap viper-delete-backward-word] 'ido-delete-backward-word-updir)) + (set-keymap-parent map + (if (eq ido-cur-item 'file) + ido-file-completion-map + ido-file-dir-completion-map))) + + ((eq ido-cur-item 'buffer) + (when ido-context-switch-command + (define-key map "\C-x\C-f" ido-context-switch-command)) + (set-keymap-parent map ido-buffer-completion-map)) + + (t + (set-keymap-parent map ido-common-completion-map))) + + (setq ido-completion-map map))) + +(defun ido-final-slash (dir &optional fix-it) + ;; return DIR if DIR has final slash. + ;; else if FIX-IT is non-nil, return DIR/ + ;; else return nil. + (setq dir (ido-name dir)) + (cond + ((string-match "/\\'" dir) dir) + ((ido-is-tramp-root dir) dir) + (fix-it (concat dir "/")) + (t nil))) + +(defun ido-no-final-slash (s) + ;; Remove optional final slash from string S + (let ((l (1- (length s)))) + (if (and (> l 0) (eq (aref s l) ?/)) + (substring s 0 l) + s))) + +(defun ido-nonreadable-directory-p (dir) + ;; Return t if dir is a directory, but not readable + ;; Do not check for non-readable directories via tramp, as this causes a premature + ;; connect on incomplete tramp paths (after entring just method:). + (let ((ido-enable-tramp-completion nil)) + (and (ido-final-slash dir) + (not (ido-is-unc-host dir)) + (file-directory-p dir) + (not (file-readable-p dir))))) + +(defun ido-directory-too-big-p (dir) + ;; Return t if dir is a directory, but too big to show + ;; Do not check for non-readable directories via tramp, as this causes a premature + ;; connect on incomplete tramp paths (after entring just method:). + (let ((ido-enable-tramp-completion nil)) + (and (numberp ido-max-directory-size) + (ido-final-slash dir) + (not (ido-is-unc-host dir)) + (file-directory-p dir) + (> (nth 7 (file-attributes dir)) ido-max-directory-size)))) + +(defun ido-set-current-directory (dir &optional subdir no-merge) + ;; Set ido's current directory to DIR or DIR/SUBDIR + (unless (and ido-enable-tramp-completion + (string-match "\\`/[^/]*@\\'" dir)) + (setq dir (ido-final-slash dir t))) + (setq ido-use-merged-list nil + ido-try-merged-list (not no-merge)) + (when subdir + (setq dir (concat dir subdir)) + (unless (and ido-enable-tramp-completion + (string-match "\\`/[^/]*@\\'" dir)) + (setq dir (ido-final-slash dir t)))) + (if (get-buffer ido-completion-buffer) + (kill-buffer ido-completion-buffer)) + (cond + ((equal dir ido-current-directory) + nil) + ((ido-is-unc-root dir) + (ido-trace "unc" dir) + (setq ido-current-directory dir) + (setq ido-directory-nonreadable nil) + (setq ido-directory-too-big nil) + t) + (t + (ido-trace "cd" dir) + (setq ido-current-directory dir) + (if (get-buffer ido-completion-buffer) + (kill-buffer ido-completion-buffer)) + (setq ido-directory-nonreadable (ido-nonreadable-directory-p dir)) + (setq ido-directory-too-big (and (not ido-directory-nonreadable) + (ido-directory-too-big-p dir))) + t))) + +(defun ido-set-current-home (&optional dir) + ;; Set ido's current directory to user's home directory + (ido-set-current-directory (expand-file-name (or dir "~/")))) + +(defun ido-record-command (command arg) + ;; Add (command arg) to command-history if ido-record-commands is t + (if ido-record-commands + (let ((cmd (list command arg))) + (if (or (not command-history) + (not (equal cmd (car command-history)))) + (setq command-history (cons cmd command-history)))))) + +(defun ido-make-prompt (item prompt) + ;; Make the prompt for ido-read-internal + (cond + ((and (memq item '(file dir)) ido-current-directory) + (let ((dirname (abbreviate-file-name ido-current-directory)) + (max-width (if (and ido-max-file-prompt-width (floatp ido-max-file-prompt-width)) + (floor (* (frame-width) ido-max-file-prompt-width)) + ido-max-file-prompt-width)) + (literal (and (boundp 'ido-find-literal) ido-find-literal "(literal) ")) + (vc-off (and ido-saved-vc-hb (not vc-handled-backends) "[-VC] ")) + (prefix nil) + (rule ido-rewrite-file-prompt-rules)) + (let ((case-fold-search nil)) + (while rule + (if (and (consp (car rule)) + (string-match (car (car rule)) dirname)) + (setq dirname + (if (stringp (cdr (car rule))) + (replace-match (cdr (car rule)) t nil dirname) + (funcall (cdr (car rule)) dirname)))) + (setq rule (cdr rule)))) + (run-hooks 'ido-rewrite-file-prompt-functions) + (concat prompt + ; (if ido-process-ignore-lists "" "&") + (or literal "") + (or vc-off "") + (or prefix "") + (let ((l (length dirname))) + (if (and max-width (> max-width 0) (> l max-width)) + (let* ((s (substring dirname (- max-width))) + (i (string-match "/" s))) + (concat "..." (if i (substring s i) s))) + dirname))))) + (t prompt))) + +;; Here is very briefly how ido-find-file works: +;; +;; (ido-find-file) +;; (ido-file-internal method) +;; set ido-current-directory +;; (ido-read-internal 'file ...) +;; (while ... +;; (ido-make-item-list ...) +;; (ido-set-matches) +;; (completing-read ... ido-text-init ...) +;; +;; ... here user is allowed to type characters and commands +;; a command may set ido-exit and call (exit-minibuffer) +;; to make ido-read-internal do advanced tasks (or return) +;; +;; ... ido-tidy and ido-exhibit are pre- and post-hooks +;; which are run before and after each user command. +;; +;; return value from completing-read is stored in ido-final-text +;; - ido-exit may cause further actions to be taken: +;; 'refresh - repeat loop (make-item-list, set-matches) +;; 'edit - edit the prompt string, then repeat loop +;; 'keep - repeat loop but don't (re)make-item-list +;; 'updir - go up one directory, repeat loop +;; else set ido-selected based on ido-final-text, +;; optionally update ido-current-directory and repeat loop, or +;; exit with the return value of ido-selected (file name) +;; selected file name is returned from ido-read-internal, +;; ido-exit and method determines what action is taken +;; e.g. the file name may be ignored or joined with ido-current-directory, and +;; the relevant function is called (find-file, write-file, etc). + +(defun ido-read-internal (item prompt history &optional default require-match initial) + "Perform the `ido-read-buffer' and `ido-read-file-name' functions. +Return the name of a buffer or file selected. +PROMPT is the prompt to give to the user. +DEFAULT if given is the default item to start with. +If REQUIRE-MATCH is non-nil, an existing file must be selected. +If INITIAL is non-nil, it specifies the initial input string." + (let + ((ido-cur-item item) + (ido-entry-buffer (current-buffer)) + (ido-process-ignore-lists t) + (ido-process-ignore-lists-inhibit nil) + (ido-set-default-item t) + ido-default-item + ido-selected + ido-final-text + (done nil) + (icomplete-mode nil) ;; prevent icomplete starting up + ;; Exported dynamic variables: + ido-cur-list + ido-ignored-list + (ido-rotate-temp nil) + (ido-keep-item-list nil) + (ido-use-merged-list nil) + (ido-try-merged-list t) + (ido-pre-merge-state nil) + (ido-case-fold ido-case-fold) + (ido-enable-prefix ido-enable-prefix) + (ido-enable-regexp ido-enable-regexp) + (ido-show-confirm-message nil) + ) + + (ido-setup-completion-map) + (setq ido-text-init initial) + (setq ido-input-stack nil) + + (run-hooks 'ido-setup-hook) + + (while (not done) + (ido-trace "\n_LOOP_" ido-text-init) + (setq ido-exit nil) + (setq ido-rescan t) + (setq ido-rotate nil) + (setq ido-text "") + (when ido-set-default-item + (setq ido-default-item + (cond + ((eq item 'buffer) + (if (bufferp default) (buffer-name default) default)) + ((stringp default) + (if (memq item '(file dir)) + (file-name-nondirectory default) + default)) + ((eq item 'file) + (and ido-enable-last-directory-history + (let ((d (assoc ido-current-directory ido-last-directory-list))) + (and d (cdr d))))))) + (if (member ido-default-item ido-ignore-item-temp-list) + (setq ido-default-item nil)) + (ido-trace "new default" ido-default-item) + (if ido-default-item + (setq ido-initial-position 0)) + (setq ido-set-default-item nil)) + + (if ido-process-ignore-lists-inhibit + (setq ido-process-ignore-lists nil)) + + (if (and ido-use-merged-list (memq ido-try-merged-list '(t wide)) (not ido-keep-item-list)) + (let ((olist ido-cur-list) + (oign ido-ignored-list) + (omat ido-matches) + (l (ido-make-merged-file-list ido-text-init + (eq ido-use-merged-list 'auto) + (eq ido-try-merged-list 'wide)))) + (ido-trace "merged" l) + (cond + ((not l) + (if (eq ido-try-merged-list 'wide) + (setq ido-pre-merge-state + (list "" ido-current-directory olist oign omat) + ido-cur-list nil + ido-ignored-list nil + ido-matches nil + ido-keep-item-list t + ido-try-merged-list (if (eq ido-use-merged-list 'auto) 'auto nil) + ido-use-merged-list nil) + (setq ido-cur-list olist + ido-ignored-list oign + ido-matches omat + ido-keep-item-list t + ido-try-merged-list (if (eq ido-use-merged-list 'auto) 'auto nil) + ido-use-merged-list nil))) + ((eq l t) + (setq ido-use-merged-list nil)) + ((eq l 'input-pending-p) + (setq ido-try-merged-list t + ido-use-merged-list nil)) + (t + (setq ido-pre-merge-state + (list ido-text-init ido-current-directory olist oign omat)) + (ido-set-current-directory (car (cdr (car l)))) + (if (ido-final-slash ido-text-init) + (setq ido-text-init "")) + (setq ido-cur-list l + ido-ignored-list nil + ido-matches l + ido-rescan nil + ido-keep-item-list t + ido-use-merged-list t) + (ido-trace "Merged" t) + )))) + + (cond + (ido-keep-item-list + (setq ido-keep-item-list nil + ido-rescan nil)) + ((eq ido-cur-item 'file) + (setq ido-ignored-list nil + ido-cur-list (and (not ido-directory-nonreadable) + (not ido-directory-too-big) + (ido-make-file-list ido-default-item)))) + ((eq ido-cur-item 'dir) + (setq ido-ignored-list nil + ido-cur-list (and (not ido-directory-nonreadable) + (not ido-directory-too-big) + (ido-make-dir-list ido-default-item)))) + ((eq ido-cur-item 'buffer) + (setq ido-ignored-list nil + ido-cur-list (ido-make-buffer-list ido-default-item))) + ((eq ido-cur-item 'list) + (setq ido-ignored-list nil + ido-cur-list (ido-make-choice-list ido-default-item))) + (t nil)) + (setq ido-rotate-temp nil) + + (if ido-process-ignore-lists-inhibit + (setq ido-process-ignore-lists t + ido-process-ignore-lists-inhibit nil)) + + (ido-set-matches) + (if (and ido-matches (eq ido-try-merged-list 'auto)) + (setq ido-try-merged-list t)) + (let ((max-mini-window-height (or ido-max-window-height + (and (boundp 'max-mini-window-height) + max-mini-window-height))) + (ido-completing-read t) + (ido-require-match require-match) + (ido-use-mycompletion-depth (1+ (minibuffer-depth))) + (show-paren-mode nil) + ;; Postpone history adding till later + (history-add-new-input nil)) + ;; prompt the user for the file name + (setq ido-exit nil) + (setq ido-final-text + (catch 'ido + (read-from-minibuffer (ido-make-prompt item prompt) + (prog1 ido-text-init + (setq ido-text-init nil)) + ido-completion-map nil history)))) + (ido-trace "read-from-minibuffer" ido-final-text) + (if (get-buffer ido-completion-buffer) + (kill-buffer ido-completion-buffer)) + + (ido-trace "\n_EXIT_" ido-exit) + + (cond + ((eq ido-exit 'refresh) + (if (and (eq ido-use-merged-list 'auto) + (or (input-pending-p))) + (setq ido-use-merged-list nil + ido-keep-item-list t)) + nil) + + ((eq ido-exit 'done) + (setq done t + ido-selected ido-text + ido-exit nil)) + + ((memq ido-exit '(edit chdir)) + (cond + ((memq ido-cur-item '(file dir)) + (let* ((read-file-name-function nil) + (edit (eq ido-exit 'edit)) + (d ido-current-directory) + (f ido-text-init) + (new t)) + (setq ido-text-init "") + (while new + (setq new (if edit + (condition-case nil + (read-file-name (concat prompt "[EDIT] ") + (expand-file-name d) + (concat d f) nil f) + (quit (concat d f))) + f) + d (or (file-name-directory new) "/") + f (file-name-nondirectory new) + edit t) + (if (or + (file-directory-p d) + (and (yes-or-no-p (format "Create directory %s? " d)) + (condition-case nil + (progn (make-directory d t) t) + (error + (message "Could not create directory") + (sit-for 1) + nil)))) + (progn + (ido-set-current-directory d nil (eq ido-exit 'chdir)) + (setq ido-text-init f + new nil)))))) + (t + (setq ido-text-init + (condition-case nil + (read-string (concat prompt "[EDIT] ") ido-final-text) + (quit ido-final-text))))) + + nil) + + ((eq ido-exit 'keep) + (setq ido-keep-item-list t)) + + ((memq ido-exit '(dired fallback find-file switch-to-buffer insert-buffer insert-file)) + (setq done t)) + + ((memq ido-exit '(updir push)) + ;; cannot go up if already at the root-dir (Unix) or at the + ;; root-dir of a certain drive (Windows or MS-DOS). + (if (ido-is-tramp-root) + (when (string-match "\\`\\(/\\([^/]+[:@]\\)*\\)\\([^/]+\\)[:@]\\'" ido-current-directory) + (setq ido-text-init (match-string 3 ido-current-directory)) + (ido-set-current-directory (match-string 1 ido-current-directory)) + (setq ido-set-default-item t)) + (unless (ido-is-root-directory) + (when (eq ido-exit 'push) + (setq ido-input-stack (cons (cons ido-cur-item ido-text) ido-input-stack)) + (setq ido-cur-item 'dir) + (setq ido-text-init (file-name-nondirectory (substring ido-current-directory 0 -1))) + (ido-trace "push" ido-input-stack)) + (ido-set-current-directory (file-name-directory (substring ido-current-directory 0 -1))) + (setq ido-set-default-item t)))) + + ((eq ido-exit 'pop) + (ido-trace "pop" ido-input-stack) + (let ((elt (car ido-input-stack))) + (setq ido-input-stack (cdr ido-input-stack)) + (ido-set-current-directory (concat ido-current-directory ido-text)) + (setq ido-cur-item (car elt)) + (setq ido-text-init (cdr elt)))) + + ((eq ido-exit 'pop-all) + (ido-trace "pop-all" ido-input-stack) + (while ido-input-stack + (let ((elt (car ido-input-stack))) + (setq ido-input-stack (cdr ido-input-stack)) + (ido-set-current-directory (concat ido-current-directory ido-text)) + (setq ido-cur-item (car elt)) + (setq ido-text-init (cdr elt))))) + + ;; Handling the require-match must be done in a better way. + ((and require-match + (not (memq require-match '(confirm confirm-after-completion))) + (not (if ido-directory-too-big + (file-exists-p (concat ido-current-directory ido-final-text)) + (ido-existing-item-p)))) + (error "Must specify valid item")) + + (t + (setq ido-selected + (if (or (eq ido-exit 'takeprompt) + (null ido-matches)) + ido-final-text + ;; else take head of list + (ido-name (car ido-matches)))) + + (cond + ((memq item '(buffer list)) + (setq done t)) + + ((string-equal "./" ido-selected) + nil) + + ((string-equal "../" ido-selected) + ;; cannot go up if already at the root-dir (Unix) or at the + ;; root-dir of a certain drive (Windows or MS-DOS). + (or (ido-is-root-directory) + (ido-set-current-directory (file-name-directory (substring ido-current-directory 0 -1)))) + (setq ido-set-default-item t)) + + ((and (string-match (if ido-enable-tramp-completion ".[:@]\\'" ".:\\'") ido-selected) + (ido-is-root-directory) ;; Ange-ftp or Tramp + (not (ido-local-file-exists-p ido-selected))) + (ido-set-current-directory ido-current-directory ido-selected) + (ido-trace "tramp prefix" ido-selected) + (if (ido-is-slow-ftp-host) + (setq ido-exit 'fallback + done t) + (setq ido-set-default-item t))) + + ((or (string-match "[/\\][^/\\]" ido-selected) + (and (memq system-type '(windows-nt ms-dos)) + (string-match "\\`[a-zA-Z]:" ido-selected))) + (ido-set-current-directory (file-name-directory ido-selected)) + (setq ido-set-default-item t)) + + ((string-match "\\`~" ido-selected) + (ido-set-current-home ido-selected)) + + ((ido-final-slash ido-selected) + (if ido-enable-last-directory-history + (let ((x (assoc ido-current-directory ido-last-directory-list))) + (if x + (setcdr x ido-selected) + (setq ido-last-directory-list + (cons (cons ido-current-directory ido-selected) ido-last-directory-list))))) + (ido-set-current-directory ido-current-directory ido-selected) + (if ido-input-stack + ; automatically pop stack elements which match existing files or directories + (let (elt) + (while (and (setq elt (car ido-input-stack)) + (file-exists-p (concat ido-current-directory (cdr elt)))) + (if (setq ido-input-stack (cdr ido-input-stack)) + (ido-set-current-directory ido-current-directory (cdr elt)) + (setq ido-text-init (cdr elt))) + (setq ido-cur-item (car elt)))) + (setq ido-set-default-item t))) + + (t + (setq done t)))))) + (add-to-history (or history 'minibuffer-history) ido-selected) + ido-selected)) + +(defun ido-edit-input () + "Edit absolute file name entered so far with ido; terminate by RET. +If cursor is not at the end of the user input, move to end of input." + (interactive) + (if (not (eobp)) + (end-of-line) + (setq ido-text-init (if ido-matches (ido-name (car ido-matches)) ido-text)) + (setq ido-exit 'edit) + (exit-minibuffer))) + +;;; MAIN FUNCTIONS +(defun ido-buffer-internal (method &optional fallback prompt default initial switch-cmd) + ;; Internal function for ido-switch-buffer and friends + (if (not ido-mode) + (progn + (run-hook-with-args 'ido-before-fallback-functions + (or fallback 'switch-to-buffer)) + (call-interactively (or fallback 'switch-to-buffer))) + (let* ((ido-context-switch-command switch-cmd) + (ido-current-directory nil) + (ido-directory-nonreadable nil) + (ido-directory-too-big nil) + (ido-use-virtual-buffers (if (eq method 'kill) + nil ;; Don't consider virtual buffers for killing + ido-use-virtual-buffers)) + (require-match (confirm-nonexistent-file-or-buffer)) + (buf (ido-read-internal 'buffer (or prompt "Buffer: ") 'ido-buffer-history default + require-match initial)) + filename) + + ;; Choose the buffer name: either the text typed in, or the head + ;; of the list of matches + + (cond + ((eq ido-exit 'find-file) + (ido-file-internal + (if (memq method '(other-window other-frame)) method ido-default-file-method) + nil nil nil nil ido-text)) + + ((eq ido-exit 'insert-file) + (ido-file-internal 'insert 'insert-file nil "Insert file: " nil ido-text 'ido-enter-insert-buffer)) + + ((eq ido-exit 'fallback) + (let ((read-buffer-function nil)) + (setq this-command (or fallback 'switch-to-buffer)) + (run-hook-with-args 'ido-before-fallback-functions this-command) + (call-interactively this-command))) + + ;; Check buf is non-nil. + ((not buf) nil) + ((= (length buf) 0) nil) + + ;; View buffer if it exists + ((get-buffer buf) + (add-to-history 'buffer-name-history buf) + (if (eq method 'insert) + (progn + (ido-record-command 'insert-buffer buf) + (push-mark + (save-excursion + (insert-buffer-substring (get-buffer buf)) + (point)))) + (ido-visit-buffer buf method t))) + + ;; check for a virtual buffer reference + ((and ido-use-virtual-buffers ido-virtual-buffers + (setq filename (assoc buf ido-virtual-buffers))) + (ido-visit-buffer (find-file-noselect (cdr filename)) method t)) + + ((and (eq ido-create-new-buffer 'prompt) + (null require-match) + (not (y-or-n-p (format "No buffer matching `%s', create one? " buf)))) + nil) + + ;; buffer doesn't exist + ((and (eq ido-create-new-buffer 'never) + (null require-match)) + (message "No buffer matching `%s'" buf)) + + ((and (eq ido-create-new-buffer 'prompt) + (null require-match) + (not (y-or-n-p (format "No buffer matching `%s', create one? " buf)))) + nil) + + ;; create a new buffer + (t + (add-to-history 'buffer-name-history buf) + (setq buf (get-buffer-create buf)) + (if (fboundp 'set-buffer-major-mode) + (set-buffer-major-mode buf)) + (ido-visit-buffer buf method t)))))) + +(defun ido-record-work-directory (&optional dir) + (when (and (numberp ido-max-work-directory-list) (> ido-max-work-directory-list 0)) + (if (and (setq dir (or dir ido-current-directory)) (> (length dir) 0)) + (let ((items ido-work-directory-list-ignore-regexps) + (case-fold-search nil)) + (while (and items dir) + (if (string-match (car items) dir) + (setq dir nil)) + (setq items (cdr items))) + (if dir + (setq ido-work-directory-list (cons dir (delete dir ido-work-directory-list)))))) + (if (> (length ido-work-directory-list) ido-max-work-directory-list) + (setcdr (nthcdr (1- ido-max-work-directory-list) ido-work-directory-list) nil)))) + +(defun ido-forget-work-directory () + (interactive) + (when (and ido-current-directory ido-work-directory-list) + (setq ido-work-directory-list (delete ido-current-directory ido-work-directory-list)) + (when ido-use-merged-list + (ido-undo-merge-work-directory) + (setq ido-exit 'refresh + ido-try-merged-list t + ido-use-merged-list t + ido-text-init ido-text + ido-rotate-temp t) + (exit-minibuffer)))) + +(defun ido-record-work-file (name) + ;; Save NAME in ido-work-file-list + (when (and (numberp ido-max-work-file-list) (> ido-max-work-file-list 0)) + (or + (and ido-work-file-list (equal (car ido-work-file-list) name)) + (setq ido-work-file-list (cons name (delete name ido-work-file-list)))) + (if (> (length ido-work-file-list) ido-max-work-file-list) + (setcdr (nthcdr (1- ido-max-work-file-list) ido-work-file-list) nil)))) + +(defun ido-expand-directory (dir) + ;; Expand DIR or use DEFAULT-DIRECTORY if nil. + ;; Add final slash to result in case it was missing from DEFAULT-DIRECTORY. + (ido-final-slash (expand-file-name (or dir default-directory)) t)) + +(defun ido-file-internal (method &optional fallback default prompt item initial switch-cmd) + ;; Internal function for ido-find-file and friends + (unless item + (setq item 'file)) + (let ((ido-current-directory (ido-expand-directory default)) + (ido-context-switch-command switch-cmd) + ido-directory-nonreadable ido-directory-too-big + filename) + + (if (or (not ido-mode) (ido-is-slow-ftp-host)) + (setq filename t + ido-exit 'fallback) + (setq ido-directory-nonreadable + (ido-nonreadable-directory-p ido-current-directory) + ido-directory-too-big + (and (not ido-directory-nonreadable) + (ido-directory-too-big-p ido-current-directory)))) + + (when (and (eq item 'file) + (or ido-use-url-at-point ido-use-filename-at-point)) + (let (fn d) + (require 'ffap) + ;; Duplicate code from ffap-guesser as we want different + ;; behavior for files and URLs. + (cond + ((with-no-warnings + (and ido-use-url-at-point + ffap-url-regexp + (ffap-fixup-url (or (ffap-url-at-point) + (ffap-gopher-at-point))))) + (setq ido-exit 'ffap + filename t)) + + ((and ido-use-filename-at-point + (setq fn (with-no-warnings + (if (eq ido-use-filename-at-point 'guess) + (ffap-guesser) + (ffap-string-at-point)))) + (not (string-match "^http:/" fn)) + (let ((absolute-fn (expand-file-name fn))) + (setq d (if (file-directory-p absolute-fn) + (file-name-as-directory absolute-fn) + (file-name-directory absolute-fn)))) + (file-directory-p d)) + (setq ido-current-directory d) + (setq initial (file-name-nondirectory fn)))))) + + (let (ido-saved-vc-hb + (vc-handled-backends (and (boundp 'vc-handled-backends) vc-handled-backends)) + (ido-work-directory-index -1) + (ido-work-file-index -1) + (ido-find-literal nil)) + + (unless filename + (setq ido-saved-vc-hb vc-handled-backends) + (let ((minibuffer-completing-file-name t)) + (setq filename (ido-read-internal item + (or prompt "Find file: ") + 'ido-file-history + (and (eq method 'alt-file) buffer-file-name) + (confirm-nonexistent-file-or-buffer) initial)))) + + ;; Choose the file name: either the text typed in, or the head + ;; of the list of matches + + (cond + ((eq ido-exit 'fallback) + ;; Need to guard setting of default-directory here, since + ;; we don't want to change directory of current buffer. + (let ((default-directory ido-current-directory) + (read-file-name-function nil)) + (setq this-command (or fallback 'find-file)) + (run-hook-with-args 'ido-before-fallback-functions this-command) + (call-interactively this-command))) + + ((eq ido-exit 'switch-to-buffer) + (ido-buffer-internal + (if (memq method '(other-window other-frame)) method ido-default-buffer-method) + nil nil nil ido-text)) + + ((eq ido-exit 'insert-buffer) + (ido-buffer-internal 'insert 'insert-buffer "Insert buffer: " nil ido-text 'ido-enter-insert-file)) + + ((eq ido-exit 'dired) + (dired (concat ido-current-directory (or ido-text "")))) + + ((eq ido-exit 'ffap) + (find-file-at-point)) + + ((eq method 'alt-file) + (ido-record-work-file filename) + (setq default-directory ido-current-directory) + (ido-record-work-directory) + (find-alternate-file filename)) + + ((memq method '(dired list-directory)) + (if (equal filename ".") + (setq filename "")) + (let* ((dirname (ido-final-slash (concat ido-current-directory filename) t)) + (file (substring dirname 0 -1))) + (cond + ((file-directory-p dirname) + (ido-record-command method dirname) + (ido-record-work-directory dirname) + (funcall method dirname)) + ((file-directory-p ido-current-directory) + (cond + ((file-exists-p file) + (ido-record-command method ido-current-directory) + (ido-record-work-directory) + (funcall method ido-current-directory) + (if (eq method 'dired) + (with-no-warnings + (dired-goto-file (expand-file-name file))))) + ((string-match "[[*?]" filename) + (setq dirname (concat ido-current-directory filename)) + (ido-record-command method dirname) + (ido-record-work-directory) + (funcall method dirname)) + ((y-or-n-p (format "Directory %s does not exist. Create it? " filename)) + (ido-record-command method dirname) + (ido-record-work-directory dirname) + (make-directory-internal dirname) + (funcall method dirname)) + (t + ;; put make-directory command on history + (ido-record-command 'make-directory dirname)))) + (t (error "No such directory"))))) + + ((eq method 'write) + (ido-record-work-file filename) + (setq default-directory ido-current-directory) + (setq filename (concat ido-current-directory filename)) + (ido-record-command 'write-file filename) + (add-to-history 'file-name-history filename) + (ido-record-work-directory) + (write-file filename t)) + + ((eq method 'read-only) + (ido-record-work-file filename) + (setq filename (concat ido-current-directory filename)) + (ido-record-command fallback filename) + (ido-record-work-directory) + (run-hook-with-args 'ido-before-fallback-functions fallback) + (funcall fallback filename)) + + ((eq method 'insert) + (ido-record-work-file filename) + (setq filename (concat ido-current-directory filename)) + (ido-record-command + (if ido-find-literal 'insert-file-literally 'insert-file) + filename) + (add-to-history 'file-name-history filename) + (ido-record-work-directory) + (insert-file-1 filename + (if ido-find-literal + #'insert-file-contents-literally + #'insert-file-contents))) + + (filename + (ido-record-work-file filename) + (setq filename (concat ido-current-directory filename)) + (ido-record-command 'find-file filename) + (add-to-history 'file-name-history filename) + (ido-record-work-directory) + (ido-visit-buffer (find-file-noselect filename nil ido-find-literal) method)))))) + +(defun ido-existing-item-p () + ;; Return non-nil if there is a matching item + (not (null ido-matches))) + +;;; COMPLETION CODE + +(defun ido-set-common-completion () + ;; Find common completion of `ido-text' in `ido-matches' + ;; The result is stored in `ido-common-match-string' + (let (val) + (setq ido-common-match-string nil) + (if (and ido-matches + (not ido-enable-regexp) ;; testing + (stringp ido-text) + (> (length ido-text) 0)) + (if (setq val (ido-find-common-substring ido-matches ido-text)) + (setq ido-common-match-string val))) + val)) + +(defun ido-complete () + "Try and complete the current pattern amongst the file names." + (interactive) + (let (res) + (cond + (ido-incomplete-regexp + ;; Do nothing + ) + ((and (memq ido-cur-item '(file dir)) + (string-match "[$]" ido-text)) + (let ((evar (substitute-in-file-name (concat ido-current-directory ido-text)))) + (if (not (file-exists-p (file-name-directory evar))) + (message "Expansion generates non-existing directory name") + (if (file-directory-p evar) + (ido-set-current-directory evar) + (let ((d (or (file-name-directory evar) "/")) + (f (file-name-nondirectory evar))) + (when (file-directory-p d) + (ido-set-current-directory d) + (setq ido-text-init f)))) + (setq ido-exit 'refresh) + (exit-minibuffer)))) + + (ido-directory-too-big + (setq ido-directory-too-big nil) + (setq ido-text-init ido-text) + (setq ido-exit 'refresh) + (exit-minibuffer)) + + ((not ido-matches) + (when ido-completion-buffer + (call-interactively (setq this-command ido-cannot-complete-command)))) + + ((and (= 1 (length ido-matches)) + (not (and ido-enable-tramp-completion + (string-equal ido-current-directory "/") + (string-match ".[@:]\\'" (ido-name (car ido-matches))))) + (not (ido-local-file-exists-p (ido-name (car ido-matches))))) + ;; only one choice, so select it. + (if (not ido-confirm-unique-completion) + (exit-minibuffer) + (setq ido-rescan (not ido-enable-prefix)) + (delete-region (minibuffer-prompt-end) (point)) + (insert (ido-name (car ido-matches))))) + + (t ;; else there could be some completions + (setq res ido-common-match-string) + (if (and (not (memq res '(t nil))) + (not (equal res ido-text))) + ;; found something to complete, so put it in the minibuffer. + (progn + ;; move exact match to front if not in prefix mode + (setq ido-rescan (not ido-enable-prefix)) + (delete-region (minibuffer-prompt-end) (point)) + (insert res)) + ;; else nothing to complete + (call-interactively (setq this-command ido-cannot-complete-command)) + ))))) + +(defun ido-complete-space () + "Try completion unless inserting the space makes sense." + (interactive) + (if (and (stringp ido-common-match-string) + (stringp ido-text) + (cond + ((> (length ido-common-match-string) (length ido-text)) + (= (aref ido-common-match-string (length ido-text)) ? )) + (ido-matches + (let (insert-space + (re (concat (regexp-quote ido-text) " ")) + (comp ido-matches)) + (while comp + (if (string-match re (ido-name (car comp))) + (setq comp nil insert-space t) + (setq comp (cdr comp)))) + insert-space)) + (t nil))) + (insert " ") + (ido-complete))) + +(defun ido-undo-merge-work-directory (&optional text try refresh) + "Undo or redo last ido directory merge operation. +If no merge has yet taken place, toggle automatic merging option." + (interactive) + (cond + (ido-pre-merge-state + (ido-set-current-directory (nth 1 ido-pre-merge-state)) + (setq ido-text-init (or text (car ido-pre-merge-state)) + ido-cur-list (nth 2 ido-pre-merge-state) + ido-ignored-list (nth 3 ido-pre-merge-state) + ido-matches (nth 4 ido-pre-merge-state) + ido-use-merged-list nil + ido-try-merged-list try + ido-keep-item-list (not refresh) + ido-rescan nil + ido-exit 'refresh + ido-pre-merge-state nil) + (exit-minibuffer)) + (text + nil) + (ido-try-merged-list + (setq ido-try-merged-list nil)) + (ido-matches + (setq ido-try-merged-list t)) + ((not ido-use-merged-list) + (ido-merge-work-directories)))) + +;;; Magic C-f + +(defun ido-magic-forward-char (arg) + "Move forward in user input or perform magic action. +If no user input is present, or at end of input, perform magic actions: +C-x C-b ... C-f switch to `ido-find-file'. +C-x C-f ... C-f fallback to non-ido `find-file'. +C-x C-d ... C-f fallback to non-ido brief `dired'. +C-x d ... C-f fallback to non-ido `dired'." + (interactive "P") + (cond + ((or arg (not (eobp))) + (forward-char (min (prefix-numeric-value arg) + (- (point-max) (point))))) + ((memq ido-cur-item '(file dir)) + (ido-fallback-command)) + (ido-context-switch-command + (call-interactively ido-context-switch-command)) + ((eq ido-cur-item 'buffer) + (ido-enter-find-file)))) + +;;; Magic C-b + +(defun ido-magic-backward-char (arg) + "Move backward in user input or perform magic action. +If no user input is present, or at start of input, perform magic actions: +C-x C-f C-b switch to `ido-switch-buffer'. +C-x C-d C-b switch to `ido-switch-buffer'. +C-x d C-b switch to `ido-switch-buffer'. +C-x C-b C-b fallback to non-ido `switch-to-buffer'." + (interactive "P") + (cond + ((or arg (> (point) (minibuffer-prompt-end))) + (forward-char + (- (min (prefix-numeric-value arg) + (- (point) (minibuffer-prompt-end)))))) + ((eq last-command this-command) + (when (and (memq ido-cur-item '(file dir)) + (not (bobp))) + (ido-push-dir))) ; else do nothing + ((eq ido-cur-item 'buffer) + (ido-fallback-command)) + (ido-context-switch-command + (call-interactively ido-context-switch-command)) + (t + (ido-enter-switch-buffer)))) + +;;; Magic C-d + +(defun ido-magic-delete-char (arg) + "Delete following char in user input or perform magic action. +If at end of user input, perform magic actions: +C-x C-f ... C-d enter `dired' on current directory." + (interactive "P") + (cond + ((or arg (not (eobp))) + (delete-char (min (prefix-numeric-value arg) + (- (point-max) (point))))) + (ido-context-switch-command + nil) + ((memq ido-cur-item '(file dir)) + (ido-enter-dired)))) + + +;;; TOGGLE FUNCTIONS + +(defun ido-toggle-case () + "Toggle the value of `ido-case-fold'." + (interactive) + (setq ido-case-fold (not ido-case-fold)) + ;; ask for list to be regenerated. + (setq ido-rescan t)) + +(defun ido-toggle-regexp () + "Toggle the value of `ido-enable-regexp'." + (interactive) + (setq ido-enable-regexp (not ido-enable-regexp)) + ;; ask for list to be regenerated. + (setq ido-rescan t)) + +(defun ido-toggle-prefix () + "Toggle the value of `ido-enable-prefix'." + (interactive) + (setq ido-enable-prefix (not ido-enable-prefix)) + ;; ask for list to be regenerated. + (setq ido-rescan t)) + +(defun ido-toggle-ignore () + "Toggle ignoring files specified with `ido-ignore-files'." + (interactive) + (if (and (not (eobp)) (> (point) (minibuffer-prompt-end))) + (goto-char (minibuffer-prompt-end)) + (if ido-directory-too-big + (progn + (message "Reading directory...") + (setq ido-directory-too-big nil)) + (setq ido-process-ignore-lists (not ido-process-ignore-lists))) + (setq ido-text-init ido-text) + (setq ido-exit 'refresh) + (exit-minibuffer))) + +(defun ido-toggle-vc () + "Disable version control for this file." + (interactive) + (if (and ido-mode (eq ido-cur-item 'file)) + (progn + (setq vc-handled-backends + (if vc-handled-backends nil ido-saved-vc-hb)) + (setq ido-text-init ido-text) + (setq ido-exit 'keep) + (exit-minibuffer)))) + +(defun ido-toggle-literal () + "Toggle literal reading of this file." + (interactive) + (if (and ido-mode (eq ido-cur-item 'file)) + (progn + (setq ido-find-literal (not ido-find-literal)) + (setq ido-text-init ido-text) + (setq ido-exit 'keep) + (exit-minibuffer)))) + +(defun ido-toggle-virtual-buffers () + "Toggle the use of virtual buffers. +See `ido-use-virtual-buffers' for explanation of virtual buffer." + (interactive) + (when (and ido-mode (eq ido-cur-item 'buffer)) + (setq ido-use-virtual-buffers (not ido-use-virtual-buffers)) + (setq ido-text-init ido-text) + (setq ido-exit 'refresh) + (exit-minibuffer))) + +(defun ido-reread-directory () + "Read current directory again. +May be useful if cached version is no longer valid, but directory +timestamp has not changed (e.g. with ftp or on Windows)." + (interactive) + (if (and ido-mode (memq ido-cur-item '(file dir))) + (progn + (if (ido-is-unc-root) + (setq ido-unc-hosts-cache t) + (ido-remove-cached-dir ido-current-directory)) + (setq ido-text-init ido-text) + (setq ido-rotate-temp t) + (setq ido-exit 'refresh) + (exit-minibuffer)))) + +(defun ido-exit-minibuffer () + "Exit minibuffer, but make sure we have a match if one is needed." + (interactive) + (if (and (or (not ido-require-match) + (if (memq ido-require-match '(confirm confirm-after-completion)) + (if (or (eq ido-cur-item 'dir) + (eq last-command this-command)) + t + (setq ido-show-confirm-message t) + nil)) + (ido-existing-item-p)) + (not ido-incomplete-regexp)) + (exit-minibuffer))) + +(defun ido-select-text () + "Select the buffer or file named by the prompt. +If no buffer or file exactly matching the prompt exists, maybe create a new one." + (interactive) + (setq ido-exit 'takeprompt) + (exit-minibuffer)) + +(defun ido-fallback-command () + "Fallback to non-ido version of current command." + (interactive) + (let ((i (length ido-text))) + (while (> i 0) + (push (aref ido-text (setq i (1- i))) unread-command-events))) + (setq ido-exit 'fallback) + (exit-minibuffer)) + +(defun ido-enter-find-file () + "Drop into `find-file' from buffer switching." + (interactive) + (setq ido-exit 'find-file) + (exit-minibuffer)) + +(defun ido-enter-switch-buffer () + "Drop into `ido-switch-buffer' from file switching." + (interactive) + (setq ido-exit 'switch-to-buffer) + (exit-minibuffer)) + +(defun ido-enter-dired () + "Drop into `dired' from file switching." + (interactive) + (setq ido-exit 'dired) + (exit-minibuffer)) + +(defun ido-enter-insert-buffer () + "Drop into `insert-buffer' from insert file." + (interactive) + (setq ido-exit 'insert-buffer) + (exit-minibuffer)) + +(defun ido-enter-insert-file () + "Drop into `insert-file' from insert buffer." + (interactive) + (setq ido-exit 'insert-file) + (exit-minibuffer)) + + +(defun ido-up-directory (&optional clear) + "Go up one directory level." + (interactive "P") + (setq ido-text-init (if clear nil ido-text)) + (setq ido-exit 'updir) + (setq ido-rotate-temp t) + (exit-minibuffer)) + +(defun ido-delete-backward-updir (count) + "Delete char backwards, or at beginning of buffer, go up one level." + (interactive "P") + (cond + ((= (minibuffer-prompt-end) (point)) + (if (not count) + (ido-up-directory t))) + ((and ido-pre-merge-state (string-equal (car ido-pre-merge-state) ido-text)) + (ido-undo-merge-work-directory (substring ido-text 0 -1) t t)) + ((eq this-original-command 'viper-backward-char) + (funcall this-original-command (prefix-numeric-value count))) + ((eq this-original-command 'viper-del-backward-char-in-insert) + (funcall this-original-command)) + (t + (delete-char (- (prefix-numeric-value count)))))) + +(defun ido-delete-backward-word-updir (count) + "Delete all chars backwards, or at beginning of buffer, go up one level." + (interactive "P") + (if (= (minibuffer-prompt-end) (point)) + (if (not count) + (ido-up-directory t)) + (if (eq this-original-command 'viper-delete-backward-word) + (funcall this-original-command (prefix-numeric-value count)) + (backward-kill-word (prefix-numeric-value count))))) + +(defun ido-get-work-directory (&optional incr must-match) + (let ((n (length ido-work-directory-list)) + (i ido-work-directory-index) + (j 0) + dir) + (if (or (not ido-text) (= (length ido-text) 0)) + (setq must-match nil)) + (while (< j n) + (setq i (+ i incr) + j (1+ j)) + (if (> incr 0) + (if (>= i n) (setq i 0)) + (if (< i 0) (setq i (1- n)))) + (setq dir (nth i ido-work-directory-list)) + (if (and dir + (not (equal dir ido-current-directory)) + (file-directory-p dir) + (or (not must-match) + ;; TODO. check for nonreadable and too-big. + (ido-set-matches-1 + (if (eq ido-cur-item 'file) + (ido-make-file-list-1 dir) + (ido-make-dir-list-1 dir))))) + (setq j n) + (setq dir nil))) + (if dir + (setq ido-work-directory-index i)) + dir)) + +(defun ido-prev-work-directory () + "Change to next working directory in list." + (interactive) + (let ((dir (ido-get-work-directory 1 ido-work-directory-match-only))) + (when dir + (ido-set-current-directory dir) + (setq ido-exit 'refresh) + (setq ido-text-init ido-text) + (setq ido-rotate-temp t) + (exit-minibuffer)))) + +(defun ido-next-work-directory () + "Change to previous working directory in list." + (interactive) + (let ((dir (ido-get-work-directory -1 ido-work-directory-match-only))) + (when dir + (ido-set-current-directory dir) + (setq ido-exit 'refresh) + (setq ido-text-init ido-text) + (setq ido-rotate-temp t) + (exit-minibuffer)))) + +(defun ido-merge-work-directories () + "Search (and merge) work directories for files matching the current input string." + (interactive) + (setq ido-use-merged-list t ido-try-merged-list t) + (setq ido-exit 'refresh) + (setq ido-text-init ido-text) + (setq ido-rotate-temp t) + (exit-minibuffer)) + +(defun ido-wide-find-file (&optional file) + "Prompt for FILE to search for using find, starting from current directory." + (interactive) + (unless file + (let ((enable-recursive-minibuffers t)) + (setq file + (condition-case nil + (read-string (concat "Wide find file: " ido-current-directory) ido-text) + (quit ""))))) + (when (> (length file) 0) + (setq ido-use-merged-list t ido-try-merged-list 'wide) + (setq ido-exit 'refresh) + (setq ido-text-init file) + (setq ido-rotate-temp t) + (exit-minibuffer))) + +(defun ido-wide-find-dir (&optional dir) + "Prompt for DIR to search for using find, starting from current directory." + (interactive) + (unless dir + (let ((enable-recursive-minibuffers t)) + (setq dir + (condition-case nil + (read-string (concat "Wide find directory: " ido-current-directory) ido-text) + (quit ""))))) + (when (> (length dir) 0) + (setq ido-use-merged-list t ido-try-merged-list 'wide) + (setq ido-exit 'refresh) + (setq ido-text-init (ido-final-slash dir t)) + (setq ido-rotate-temp t) + (exit-minibuffer))) + +(defun ido-wide-find-dir-or-delete-dir (&optional dir) + "Prompt for DIR to search for using find, starting from current directory. +If input stack is non-empty, delete current directory component." + (interactive) + (if ido-input-stack + (ido-delete-backward-word-updir 1) + (ido-wide-find-dir))) + +(defun ido-take-first-match () + "Use first matching item as input text." + (interactive) + (when ido-matches + (setq ido-text-init (ido-name (car ido-matches))) + (setq ido-exit 'refresh) + (exit-minibuffer))) + +(defun ido-push-dir () + "Move to previous directory in file name, push current input on stack." + (interactive) + (setq ido-exit 'push) + (exit-minibuffer)) + +(defun ido-push-dir-first () + "Move to previous directory in file name, push first match on stack." + (interactive) + (if ido-matches + (setq ido-text (ido-name (car ido-matches)))) + (setq ido-exit 'push) + (exit-minibuffer)) + +(defun ido-pop-dir (arg) + "Pop directory from input stack back to input. +With \\[universal-argument], pop all elements." + (interactive "P") + (when ido-input-stack + (setq ido-exit (if arg 'pop-all 'pop)) + (exit-minibuffer))) + +(defun ido-wide-find-file-or-pop-dir (arg) + (interactive "P") + (if ido-input-stack + (ido-pop-dir arg) + (ido-wide-find-file))) + +(defun ido-make-directory (&optional dir) + "Prompt for DIR to create in current directory." + (interactive) + (unless dir + (let ((enable-recursive-minibuffers t)) + (setq dir + (read-string (concat "Make directory: " ido-current-directory) ido-text)))) + (when (> (length dir) 0) + (setq dir (concat ido-current-directory dir)) + (unless (file-exists-p dir) + (make-directory dir t) + (ido-set-current-directory dir) + (setq ido-exit 'refresh) + (setq ido-text-init nil) + (setq ido-rotate-temp t) + (exit-minibuffer)))) + +(defun ido-get-work-file (incr) + (let ((n (length ido-work-file-list)) + (i (+ ido-work-file-index incr)) + name) + (if (> incr 0) + (if (>= i n) (setq i 0)) + (if (< i 0) (setq i (1- n)))) + (setq name (nth i ido-work-file-list)) + (setq ido-work-file-index i) + name)) + +(defun ido-prev-work-file () + "Change to next working file name in list." + (interactive) + (let ((name (ido-get-work-file 1))) + (when name + (setq ido-text-init name) + (setq ido-exit 'refresh) + (exit-minibuffer)))) + +(defun ido-next-work-file () + "Change to previous working file name in list." + (interactive) + (let ((name (ido-get-work-file -1))) + (when name + (setq ido-text-init name) + (setq ido-exit 'refresh) + (exit-minibuffer)))) + +(defun ido-copy-current-file-name (all) + "Insert file name of current buffer. +If repeated, insert text from buffer instead." + (interactive "P") + (let* ((bfname (or (buffer-file-name ido-entry-buffer) + (buffer-name ido-entry-buffer))) + (name (and bfname (file-name-nondirectory bfname)))) + (when name + (setq ido-text-init + (if (or all + (eq last-command this-command) + (not (equal (file-name-directory bfname) ido-current-directory)) + (not (string-match "\\.[^.]*\\'" name))) + name + (substring name 0 (1+ (match-beginning 0))))) + (setq ido-exit 'refresh + ido-try-merged-list nil) + (exit-minibuffer)))) + +(defun ido-copy-current-word (all) + "Insert current word (file or directory name) from current buffer." + (interactive "P") + (let ((word (with-current-buffer ido-entry-buffer + (let ((p (point)) start-line end-line start-name name) + (if (and mark-active (/= p (mark))) + (setq start-name (mark)) + (beginning-of-line) + (setq start-line (point)) + (end-of-line) + (setq end-line (point)) + (goto-char p) + (if (re-search-backward "[^-_a-zA-Z0-9:./\\~@]" start-line 1) + (forward-char 1)) + (setq start-name (point)) + (re-search-forward "[-_a-zA-Z0-9:./\\~@]*" end-line 1) + (if (= start-name (point)) + (setq start-name nil))) + (and start-name + (buffer-substring-no-properties start-name (point))))))) + (if (cond + ((not word) nil) + ((string-match "\\`[~/]" word) + (setq ido-text-init word + ido-try-merged-list nil + ido-exit 'chdir)) + ((string-match "/" word) + (setq ido-text-init (concat ido-current-directory word) + ido-try-merged-list nil + ido-exit 'chdir)) + (t + (setq ido-text-init word + ido-try-merged-list nil + ido-exit 'refresh))) + (exit-minibuffer)))) + +(defun ido-next-match () + "Put first element of `ido-matches' at the end of the list." + (interactive) + (if ido-matches + (let ((next (cadr ido-matches))) + (setq ido-cur-list (ido-chop ido-cur-list next)) + (setq ido-matches (ido-chop ido-matches next)) + (setq ido-rescan nil)))) + +(defun ido-prev-match () + "Put last element of `ido-matches' at the front of the list." + (interactive) + (if ido-matches + (let ((prev (car (last ido-matches)))) + (setq ido-cur-list (ido-chop ido-cur-list prev)) + (setq ido-matches (ido-chop ido-matches prev)) + (setq ido-rescan nil)))) + +(defun ido-next-match-dir () + "Find next directory in match list. +If work directories have been merged, cycle through directories for +first matching file." + (interactive) + (if ido-use-merged-list + (if ido-matches + (let* ((elt (car ido-matches)) + (dirs (cdr elt))) + (when (> (length dirs) 1) + (setcdr elt (ido-chop dirs (cadr dirs)))) + (setq ido-rescan nil))) + (let ((cnt (length ido-matches)) + (i 1)) + (while (and (< i cnt) (not (ido-final-slash (nth i ido-matches)))) + (setq i (1+ i))) + (if (< i cnt) + (setq ido-cur-list (ido-chop ido-cur-list (nth i ido-matches))))))) + +(defun ido-prev-match-dir () + "Find previous directory in match list. +If work directories have been merged, cycle through directories +for first matching file." + (interactive) + (if ido-use-merged-list + (if ido-matches + (let* ((elt (car ido-matches)) + (dirs (cdr elt))) + (when (> (length dirs) 1) + (setcdr elt (ido-chop dirs (car (last dirs))))) + (setq ido-rescan nil))) + (let* ((cnt (length ido-matches)) + (i (1- cnt))) + (while (and (> i 0) (not (ido-final-slash (nth i ido-matches)))) + (setq i (1- i))) + (if (> i 0) + (setq ido-cur-list (ido-chop ido-cur-list (nth i ido-matches))))))) + +(defun ido-restrict-to-matches () + "Set current item list to the currently matched items." + (interactive) + (when ido-matches + (setq ido-cur-list ido-matches + ido-text-init "" + ido-rescan nil + ido-exit 'keep) + (exit-minibuffer))) + +(defun ido-chop (items elem) + "Remove all elements before ELEM and put them at the end of ITEMS." + (let ((ret nil) + (next nil) + (sofar nil)) + (while (not ret) + (setq next (car items)) + (if (equal next elem) + (setq ret (append items (nreverse sofar))) + ;; else + (progn + (setq items (cdr items)) + (setq sofar (cons next sofar))))) + ret)) + +(defun ido-name (item) + ;; Return file name for current item, whether in a normal list + ;; or a merged work directory list. + (if (consp item) (car item) item)) + + +;;; CREATE LIST OF ALL CURRENT FILES + +(defun ido-all-completions () + ;; Return unsorted list of all competions. + (let ((ido-process-ignore-lists nil) + (ido-directory-too-big nil)) + (cond + ((eq ido-cur-item 'file) + (ido-make-file-list-1 ido-current-directory)) + ((eq ido-cur-item 'dir) + (ido-make-dir-list-1 ido-current-directory)) + ((eq ido-cur-item 'buffer) + (ido-make-buffer-list-1)) + ((eq ido-cur-item 'list) + ido-choice-list) + (t nil)))) + + +;; File list sorting + +(defun ido-file-lessp (a b) + ;; Simple compare two file names. + (string-lessp (ido-no-final-slash a) (ido-no-final-slash b))) + + +(defun ido-file-extension-lessp (a b) + ;; Compare file names according to ido-file-extensions-order list. + (let ((n (compare-strings a 0 nil b 0 nil nil)) + lessp p) + (if (eq n t) + nil + (if (< n 0) + (setq n (1- (- n)) + p a a b b p + lessp t) + (setq n (1- n))) + (cond + ((= n 0) + lessp) + ((= (aref a n) ?.) + (ido-file-extension-aux a b n lessp)) + (t + (while (and (> n 2) (/= (aref a n) ?.)) + (setq n (1- n))) + (if (> n 1) + (ido-file-extension-aux a b n lessp) + lessp)))))) + +(defun ido-file-extension-aux (a b n lessp) + (let ((oa (ido-file-extension-order a n)) + (ob (ido-file-extension-order b n))) + (cond + ((and oa ob) + (cond + ((= oa ob) + lessp) + (lessp + (> oa ob)) + (t + (< oa ob)))) + (oa + (not lessp)) + (ob + lessp) + (t + lessp)))) + +(defun ido-file-extension-order (s n) + (let ((l ido-file-extensions-order) + (i 0) o do) + (while l + (cond + ((eq (car l) t) + (setq do i + l (cdr l))) + ((eq (compare-strings s n nil (car l) 0 nil nil) t) + (setq o i + l nil)) + (t + (setq l (cdr l)))) + (setq i (1+ i))) + (or o do))) + + +(defun ido-sort-merged-list (items promote) + ;; Input is list of ("file" . "dir") cons cells. + ;; Output is sorted list of ("file "dir" ...) lists + (let ((l (sort items (lambda (a b) (string-lessp (car b) (car a))))) + res a cur dirs) + (while l + (setq a (car l) + l (cdr l)) + (if (and res (string-equal (car (car res)) (car a))) + (progn + (setcdr (car (if cur (cdr res) res)) (cons (cdr a) (cdr (car res)))) + (if (and promote (string-equal ido-current-directory (cdr a))) + (setq cur t))) + (setq res (cons (list (car a) (cdr a)) res) + cur nil))) + res)) + +(defun ido-wide-find-dirs-or-files (dir file &optional prefix finddir) + ;; As ido-run-find-command, but returns a list of cons pairs ("file" . "dir") + (let ((filenames + (split-string + (shell-command-to-string + (concat "find " + (shell-quote-argument dir) + " -name " + (shell-quote-argument + (concat (if prefix "" "*") file "*")) + " -type " (if finddir "d" "f") " -print")))) + filename d f + res) + (while filenames + (setq filename (car filenames) + filenames (cdr filenames)) + (if (and (string-match "^/" filename) + (file-exists-p filename)) + (setq d (file-name-directory filename) + f (file-name-nondirectory filename) + res (cons (cons (if finddir (ido-final-slash f t) f) d) res)))) + res)) + +(defun ido-flatten-merged-list (items) + ;; Create a list of directory names based on a merged directory list. + (let (res) + (while items + (let* ((item (car items)) + (file (car item)) + (dirs (cdr item))) + (while dirs + (setq res (cons (concat (car dirs) file) res) + dirs (cdr dirs)))) + (setq items (cdr items))) + res)) + + +(defun ido-make-merged-file-list-1 (text auto wide) + (let (res) + (if (and (ido-final-slash text) ido-dir-file-cache) + (if wide + (setq res (ido-wide-find-dirs-or-files + ido-current-directory (substring text 0 -1) ido-enable-prefix t)) + ;; Use list of cached directories + (let ((re (concat (regexp-quote (substring text 0 -1)) "[^/:]*/\\'")) + (dirs ido-dir-file-cache) + dir b d f) + (if nil ;; simple + (while dirs + (setq dir (car (car dirs)) + dirs (cdr dirs)) + (when (and (string-match re dir) + (not (ido-ignore-item-p dir ido-ignore-directories-merge)) + (file-directory-p dir)) + (setq b (substring dir 0 -1) + f (concat (file-name-nondirectory b) "/") + d (file-name-directory b) + res (cons (cons f d) res)))) + (while dirs + (setq dir (car dirs) + d (car dir) + dirs (cdr dirs)) + (when (not (ido-ignore-item-p d ido-ignore-directories-merge)) + (setq dir (cdr (cdr dir))) + (while dir + (setq f (car dir) + dir (cdr dir)) + (if (and (string-match re f) + (not (ido-ignore-item-p f ido-ignore-directories))) + (setq res (cons (cons f d) res))))) + (if (and auto (input-pending-p)) + (setq dirs nil + res t)))))) + (if wide + (setq res (ido-wide-find-dirs-or-files + ido-current-directory text ido-enable-prefix nil)) + (let ((ido-text text) + (dirs ido-work-directory-list) + (must-match (and text (> (length text) 0))) + dir fl) + (if (and auto (not (member ido-current-directory dirs))) + (setq dirs (cons ido-current-directory dirs))) + (while dirs + (setq dir (car dirs) + dirs (cdr dirs)) + (when (and dir (stringp dir) + (or ido-merge-ftp-work-directories + (not (ido-is-ftp-directory dir))) + (file-directory-p dir) + ;; TODO. check for nonreadable and too-big. + (setq fl (if (eq ido-cur-item 'file) + (ido-make-file-list-1 dir t) + (ido-make-dir-list-1 dir t)))) + (if must-match + (setq fl (ido-set-matches-1 fl))) + (if fl + (setq res (nconc fl res)))) + (if (and auto (input-pending-p)) + (setq dirs nil + res t)))))) + res)) + +(defun ido-make-merged-file-list (text auto wide) + (let (res) + (message "Searching for `%s'...." text) + (condition-case nil + (if (eq t (setq res + (while-no-input + (ido-make-merged-file-list-1 text auto wide)))) + (setq res 'input-pending-p)) + (quit + (setq res t + ido-try-merged-list nil + ido-use-merged-list nil))) + (when (and res (listp res)) + (setq res (ido-sort-merged-list res auto))) + (when (and (or ido-rotate-temp ido-rotate-file-list-default) + (listp res) + (> (length text) 0)) + (let ((elt (assoc text res))) + (when (and elt (not (eq elt (car res)))) + (setq res (delq elt res)) + (setq res (cons elt res))))) + (message nil) + res)) + +(defun ido-make-buffer-list-1 (&optional frame visible) + ;; Return list of non-ignored buffer names + (delq nil + (mapcar + (lambda (x) + (let ((name (buffer-name x))) + (if (not (or (ido-ignore-item-p name ido-ignore-buffers) (member name visible))) + name))) + (buffer-list frame)))) + +(defun ido-make-buffer-list (default) + ;; Return the current list of buffers. + ;; Currently visible buffers are put at the end of the list. + ;; The hook `ido-make-buffer-list-hook' is run after the list has been + ;; created to allow the user to further modify the order of the buffer names + ;; in this list. If DEFAULT is non-nil, and corresponds to an existing buffer, + ;; it is put to the start of the list. + (let* ((ido-current-buffers (ido-get-buffers-in-frames 'current)) + (ido-temp-list (ido-make-buffer-list-1 (selected-frame) ido-current-buffers))) + (if ido-temp-list + (nconc ido-temp-list ido-current-buffers) + (setq ido-temp-list ido-current-buffers)) + (if default + (setq ido-temp-list + (cons default (delete default ido-temp-list)))) + (if ido-use-virtual-buffers + (ido-add-virtual-buffers-to-list)) + (run-hooks 'ido-make-buffer-list-hook) + ido-temp-list)) + +(defun ido-add-virtual-buffers-to-list () + "Add recently visited files, and bookmark files, to the buffer list. +This is to make them appear as if they were \"virtual buffers\"." + ;; If no buffers matched, and virtual buffers are being used, then + ;; consult the list of past visited files, to see if we can find + ;; the file which the user might thought was still open. + (unless recentf-mode (recentf-mode 1)) + (setq ido-virtual-buffers nil) + (let (name) + (dolist (head recentf-list) + (and (setq name (file-name-nondirectory head)) + (null (get-file-buffer head)) + (not (assoc name ido-virtual-buffers)) + (not (member name ido-temp-list)) + (not (ido-ignore-item-p name ido-ignore-buffers)) + ;;(file-exists-p head) + (push (cons name head) ido-virtual-buffers)))) + (when ido-virtual-buffers + (if ido-use-faces + (dolist (comp ido-virtual-buffers) + (put-text-property 0 (length (car comp)) + 'face 'ido-virtual + (car comp)))) + (setq ido-temp-list + (nconc ido-temp-list + (nreverse (mapcar #'car ido-virtual-buffers)))))) + +(defun ido-make-choice-list (default) + ;; Return the current list of choices. + ;; If DEFAULT is non-nil, and corresponds to an element of choices, + ;; it is put to the start of the list. + (let ((ido-temp-list ido-choice-list)) + (if default + (progn + (setq ido-temp-list + (delete default ido-temp-list)) + (setq ido-temp-list + (cons default ido-temp-list)))) + ; (run-hooks 'ido-make-choice-list-hook) + ido-temp-list)) + +(defun ido-to-end (items) + ;; Move the elements from ITEMS to the end of `ido-temp-list' + (mapc + (lambda (elem) + (setq ido-temp-list (delq elem ido-temp-list))) + items) + (if ido-temp-list + (nconc ido-temp-list items) + (setq ido-temp-list items))) + +(declare-function tramp-tramp-file-p "tramp" (name)) + +(defun ido-file-name-all-completions-1 (dir) + (cond + ((ido-nonreadable-directory-p dir) '()) + ;; do not check (ido-directory-too-big-p dir) here. + ;; Caller must have done that if necessary. + + ((and ido-enable-tramp-completion + (or (fboundp 'tramp-completion-mode-p) + (require 'tramp nil t)) + (string-match "\\`/[^/]+[:@]\\'" dir)) + ;; Strip method:user@host: part of tramp completions. + ;; Tramp completions do not include leading slash. + (let* ((len (1- (length dir))) + (non-essential t) + (compl + (or (file-name-all-completions "" dir) + ;; work around bug in ange-ftp. + ;; /ftp:user@host: => nil + ;; /ftp:user@host:./ => ok + (and + (not (string= "/ftp:" dir)) + (tramp-tramp-file-p dir) + (fboundp 'tramp-ftp-file-name-p) + (funcall 'tramp-ftp-file-name-p dir) + (string-match ":\\'" dir) + (file-name-all-completions "" (concat dir "./")))))) + (if (and compl + (> (length (car compl)) len) + (string= (substring (car compl) 0 len) (substring dir 1))) + (mapcar (lambda (c) (substring c len)) compl) + compl))) + (t + (file-name-all-completions "" dir)))) + +(defun ido-file-name-all-completions (dir) + ;; Return name of all files in DIR + ;; Uses and updates ido-dir-file-cache + (cond + ((ido-is-unc-root dir) + (mapcar + (lambda (host) + (if (string-match "/\\'" host) host (concat host "/"))) + (ido-unc-hosts t))) + ((and (numberp ido-max-dir-file-cache) (> ido-max-dir-file-cache 0) + (stringp dir) (> (length dir) 0) + (ido-may-cache-directory dir)) + (let* ((cached (assoc dir ido-dir-file-cache)) + (ctime (nth 1 cached)) + (ftp (ido-is-ftp-directory dir)) + (unc (ido-is-unc-host dir)) + (attr (if (or ftp unc) nil (file-attributes dir))) + (mtime (nth 5 attr)) + valid) + (when cached ; should we use the cached entry ? + (cond + (ftp + (setq valid (and (eq (car ctime) 'ftp) + (ido-cache-ftp-valid (cdr ctime))))) + (unc + (setq valid (and (eq (car ctime) 'unc) + (ido-cache-unc-valid (cdr ctime))))) + (t + (if attr + (setq valid (and (= (car ctime) (car mtime)) + (= (car (cdr ctime)) (car (cdr mtime)))))))) + (unless valid + (setq ido-dir-file-cache (delq cached ido-dir-file-cache) + cached nil))) + (unless cached + (cond + (unc + (setq mtime (cons 'unc (ido-time-stamp)))) + ((and ftp (file-readable-p dir)) + (setq mtime (cons 'ftp (ido-time-stamp))))) + (if mtime + (setq cached (cons dir (cons mtime (ido-file-name-all-completions-1 dir))) + ido-dir-file-cache (cons cached ido-dir-file-cache))) + (if (> (length ido-dir-file-cache) ido-max-dir-file-cache) + (setcdr (nthcdr (1- ido-max-dir-file-cache) ido-dir-file-cache) nil))) + (and cached + (cdr (cdr cached))))) + (t + (ido-file-name-all-completions-1 dir)))) + +(defun ido-remove-cached-dir (dir) + ;; Remove dir from ido-dir-file-cache + (if (and ido-dir-file-cache + (stringp dir) (> (length dir) 0)) + (let ((cached (assoc dir ido-dir-file-cache))) + (if cached + (setq ido-dir-file-cache (delq cached ido-dir-file-cache)))))) + + +(defun ido-make-file-list-1 (dir &optional merged) + ;; Return list of non-ignored files in DIR + ;; If MERGED is non-nil, each file is cons'ed with DIR + (and (or (ido-is-tramp-root dir) (ido-is-unc-root dir) + (file-directory-p dir)) + (delq nil + (mapcar + (lambda (name) + (if (not (ido-ignore-item-p name ido-ignore-files t)) + (if merged (cons name dir) name))) + (ido-file-name-all-completions dir))))) + +(defun ido-make-file-list (default) + ;; Return the current list of files. + ;; Currently visible files are put at the end of the list. + ;; The hook `ido-make-file-list-hook' is run after the list has been + ;; created to allow the user to further modify the order of the file names + ;; in this list. + (let ((ido-temp-list (ido-make-file-list-1 ido-current-directory))) + (setq ido-temp-list (sort ido-temp-list + (if ido-file-extensions-order + #'ido-file-extension-lessp + #'ido-file-lessp))) + (unless (ido-is-tramp-root ido-current-directory) + (let ((default-directory ido-current-directory)) + (ido-to-end ;; move ftp hosts and visited files to end + (delq nil (mapcar + (lambda (x) (if (or (and (string-match ".:\\'" x) + (not (ido-local-file-exists-p x))) + (and (not (ido-final-slash x)) + (let (file-name-handler-alist) + (get-file-buffer x)))) x)) + ido-temp-list))))) + (ido-to-end ;; move . files to end + (delq nil (mapcar + (lambda (x) (if (string-equal (substring x 0 1) ".") x)) + ido-temp-list))) + (if (and default (member default ido-temp-list)) + (if (or ido-rotate-temp ido-rotate-file-list-default) + (unless (equal default (car ido-temp-list)) + (let ((l ido-temp-list) k) + (while (and l (cdr l) (not (equal default (car (cdr l))))) + (setq l (cdr l))) + (setq k (cdr l)) + (setcdr l nil) + (nconc k ido-temp-list) + (setq ido-temp-list k))) + (setq ido-temp-list + (delete default ido-temp-list)) + (setq ido-temp-list + (cons default ido-temp-list)))) + (when ido-show-dot-for-dired + (setq ido-temp-list (delete "." ido-temp-list)) + (setq ido-temp-list (cons "." ido-temp-list))) + (run-hooks 'ido-make-file-list-hook) + ido-temp-list)) + +(defun ido-make-dir-list-1 (dir &optional merged) + ;; Return list of non-ignored subdirs in DIR + ;; If MERGED is non-nil, each subdir is cons'ed with DIR + (and (or (ido-is-tramp-root dir) (file-directory-p dir)) + (delq nil + (mapcar + (lambda (name) + (and (ido-final-slash name) (not (ido-ignore-item-p name ido-ignore-directories)) + (if merged (cons name dir) name))) + (ido-file-name-all-completions dir))))) + +(defun ido-make-dir-list (default) + ;; Return the current list of directories. + ;; The hook `ido-make-dir-list-hook' is run after the list has been + ;; created to allow the user to further modify the order of the + ;; directory names in this list. + (let ((ido-temp-list (ido-make-dir-list-1 ido-current-directory))) + (setq ido-temp-list (sort ido-temp-list #'ido-file-lessp)) + (ido-to-end ;; move . files to end + (delq nil (mapcar + (lambda (x) (if (string-equal (substring x 0 1) ".") x)) + ido-temp-list))) + (if (and default (member default ido-temp-list)) + (if (or ido-rotate-temp ido-rotate-file-list-default) + (unless (equal default (car ido-temp-list)) + (let ((l ido-temp-list) k) + (while (and l (cdr l) (not (equal default (car (cdr l))))) + (setq l (cdr l))) + (setq k (cdr l)) + (setcdr l nil) + (nconc k ido-temp-list) + (setq ido-temp-list k))) + (setq ido-temp-list + (delete default ido-temp-list)) + (setq ido-temp-list + (cons default ido-temp-list)))) + (setq ido-temp-list (delete "." ido-temp-list)) + (unless ido-input-stack + (setq ido-temp-list (cons "." ido-temp-list))) + (run-hooks 'ido-make-dir-list-hook) + ido-temp-list)) + +;; List of the files visible in the current frame. +(defvar ido-bufs-in-frame) + +(defun ido-get-buffers-in-frames (&optional current) + ;; Return the list of buffers that are visible in the current frame. + ;; If optional argument `current' is given, restrict searching to the + ;; current frame, rather than all frames, regardless of value of + ;; `ido-all-frames'. + (let ((ido-bufs-in-frame nil)) + (walk-windows 'ido-get-bufname nil + (if current + nil + ido-all-frames)) + ido-bufs-in-frame)) + +(defun ido-get-bufname (win) + ;; Used by `ido-get-buffers-in-frames' to walk through all windows + (let ((buf (buffer-name (window-buffer win)))) + (unless (or (member buf ido-bufs-in-frame) + (member buf ido-ignore-item-temp-list)) + ;; Only add buf if it is not already in list. + ;; This prevents same buf in two different windows being + ;; put into the list twice. + (setq ido-bufs-in-frame + (cons buf ido-bufs-in-frame))))) + +;;; FIND MATCHING ITEMS + +(defun ido-set-matches-1 (items &optional do-full) + ;; Return list of matches in items + (let* ((case-fold-search ido-case-fold) + (slash (and (not ido-enable-prefix) (ido-final-slash ido-text))) + (text (if slash (substring ido-text 0 -1) ido-text)) + (rex0 (if ido-enable-regexp text (regexp-quote text))) + (rexq (concat rex0 (if slash ".*/" ""))) + (re (if ido-enable-prefix (concat "\\`" rexq) rexq)) + (full-re (and do-full (not ido-enable-regexp) (not (string-match "\$\\'" rex0)) + (concat "\\`" rex0 (if slash "/" "") "\\'"))) + (suffix-re (and do-full slash + (not ido-enable-regexp) (not (string-match "\$\\'" rex0)) + (concat rex0 "/\\'"))) + (prefix-re (and full-re (not ido-enable-prefix) + (concat "\\`" rexq))) + (non-prefix-dot (or (not ido-enable-dot-prefix) + (not ido-process-ignore-lists) + ido-enable-prefix + (= (length ido-text) 0))) + full-matches suffix-matches prefix-matches matches) + (setq ido-incomplete-regexp nil) + (condition-case error + (mapc + (lambda (item) + (let ((name (ido-name item))) + (if (and (or non-prefix-dot + (if (= (aref ido-text 0) ?.) + (= (aref name 0) ?.) + (/= (aref name 0) ?.))) + (string-match re name)) + (cond + ((and (eq ido-cur-item 'buffer) + (or (not (stringp ido-default-item)) + (not (string= name ido-default-item))) + (string= name (buffer-name ido-entry-buffer))) + (setq matches (cons item matches))) + ((and full-re (string-match full-re name)) + (setq full-matches (cons item full-matches))) + ((and suffix-re (string-match suffix-re name)) + (setq suffix-matches (cons item suffix-matches))) + ((and prefix-re (string-match prefix-re name)) + (setq prefix-matches (cons item prefix-matches))) + (t (setq matches (cons item matches)))))) + t) + items) + (invalid-regexp + (setq ido-incomplete-regexp t + ;; Consider the invalid regexp message internally as a + ;; special-case single match, and handle appropriately + ;; elsewhere. + matches (cdr error)))) + (when prefix-matches + (ido-trace "prefix match" prefix-matches) + ;; Bug#2042. + (setq matches (nconc prefix-matches matches))) + (when suffix-matches + (ido-trace "suffix match" (list text suffix-re suffix-matches)) + (setq matches (nconc suffix-matches matches))) + (when full-matches + (ido-trace "full match" (list text full-re full-matches)) + (setq matches (nconc full-matches matches))) + (when (and (null matches) + ido-enable-flex-matching + (> (length ido-text) 1) + (not ido-enable-regexp)) + (setq re (mapconcat #'regexp-quote (split-string ido-text "") ".*")) + (if ido-enable-prefix + (setq re (concat "\\`" re))) + (mapc + (lambda (item) + (let ((name (ido-name item))) + (if (string-match re name) + (setq matches (cons item matches))))) + items)) + matches)) + + +(defun ido-set-matches () + ;; Set `ido-matches' to the list of items matching prompt + (when ido-rescan + (setq ido-matches (ido-set-matches-1 (reverse ido-cur-list) (not ido-rotate)) + ido-rotate nil))) + +(defun ido-ignore-item-p (name re-list &optional ignore-ext) + ;; Return t if the buffer or file NAME should be ignored. + (or (member name ido-ignore-item-temp-list) + (and + ido-process-ignore-lists re-list + (save-match-data + (let ((ext-list (and ignore-ext ido-ignore-extensions + completion-ignored-extensions)) + (case-fold-search ido-case-fold) + ignorep nextstr + (flen (length name)) slen) + (while ext-list + (setq nextstr (car ext-list)) + (if (cond + ((stringp nextstr) + (and (>= flen (setq slen (length nextstr))) + (string-equal (substring name (- flen slen)) nextstr))) + ((functionp nextstr) (funcall nextstr name)) + (t nil)) + (setq ignorep t + ext-list nil + re-list nil) + (setq ext-list (cdr ext-list)))) + (while re-list + (setq nextstr (car re-list)) + (if (cond + ((stringp nextstr) (string-match nextstr name)) + ((functionp nextstr) (funcall nextstr name)) + (t nil)) + (setq ignorep t + re-list nil) + (setq re-list (cdr re-list)))) + ;; return the result + (if ignorep + (setq ido-ignored-list (cons name ido-ignored-list))) + ignorep))))) + +;; Private variable used by `ido-word-matching-substring'. +(defvar ido-change-word-sub) + +(defun ido-find-common-substring (items subs) + ;; Return common string following SUBS in each element of ITEMS. + (let (res + alist + ido-change-word-sub) + (setq ido-change-word-sub + (if ido-enable-regexp + subs + (regexp-quote subs))) + (setq res (mapcar #'ido-word-matching-substring items)) + (setq res (delq nil res)) ;; remove any nil elements (shouldn't happen) + (setq alist (mapcar #'ido-makealist res)) ;; could use an OBARRAY + + ;; try-completion returns t if there is an exact match. + (let* ((completion-ignore-case ido-case-fold) + (comp (try-completion subs alist))) + (if (eq comp t) + subs + comp)))) + +(defun ido-word-matching-substring (word) + ;; Return part of WORD before 1st match to `ido-change-word-sub'. + ;; If `ido-change-word-sub' cannot be found in WORD, return nil. + (let ((case-fold-search ido-case-fold)) + (let ((m (string-match ido-change-word-sub (ido-name word)))) + (if m + (substring (ido-name word) m) + ;; else no match + nil)))) + +(defun ido-makealist (res) + ;; Return dotted pair (RES . 1). + (cons res 1)) + +(defun ido-choose-completion-string (choice &rest ignored) + (when (ido-active) + ;; Insert the completion into the buffer where completion was requested. + (if (get-buffer ido-completion-buffer) + (kill-buffer ido-completion-buffer)) + (cond + ((ido-active t) ;; ido-use-merged-list + (setq ido-current-directory "" + ido-text choice + ido-exit 'done)) + ((not (ido-final-slash choice)) + (setq ido-text choice + ido-exit 'done)) + (t + (ido-set-current-directory ido-current-directory choice) + (setq ido-exit 'refresh))) + (exit-minibuffer) + t)) + +(defun ido-completion-help () + "Show possible completions in a *File Completions* buffer." + (interactive) + (setq ido-rescan nil) + (let ((temp-buf (get-buffer ido-completion-buffer)) + display-it full-list) + (if (and (eq last-command this-command) temp-buf) + ;; scroll buffer + (let (win (buf (current-buffer))) + (display-buffer temp-buf nil nil) + (set-buffer temp-buf) + (setq win (get-buffer-window temp-buf)) + (if (pos-visible-in-window-p (point-max) win) + (if (or ido-completion-buffer-all-completions + (boundp 'ido-completion-buffer-full)) + (set-window-start win (point-min)) + (with-no-warnings + (set (make-local-variable 'ido-completion-buffer-full) t)) + (setq full-list t + display-it t)) + (scroll-other-window)) + (set-buffer buf)) + (setq display-it t)) + (if display-it + (with-output-to-temp-buffer ido-completion-buffer + (let ((completion-list (sort + (cond + (ido-directory-too-big + (message "Reading directory...") + (setq ido-directory-too-big nil + ido-ignored-list nil + ido-cur-list (ido-all-completions) + ido-rescan t) + (ido-set-matches) + (or ido-matches ido-cur-list)) + (ido-use-merged-list + (ido-flatten-merged-list (or ido-matches ido-cur-list))) + ((or full-list ido-completion-buffer-all-completions) + (ido-all-completions)) + (t + (copy-sequence (or ido-matches ido-cur-list)))) + #'ido-file-lessp))) + (if (featurep 'xemacs) + ;; XEmacs extents are put on by default, doesn't seem to be + ;; any way of switching them off. + ;; This obscure code avoids a byte compiler warning in Emacs. + (let ((f 'display-completion-list)) + (funcall f completion-list + :help-string "ido " + :activate-callback + '(lambda (x y z) (message "Doesn't work yet, sorry!")))) + ;; else running Emacs + ;;(add-hook 'completion-setup-hook 'completion-setup-function) + (display-completion-list completion-list))))))) + +;;; KILL CURRENT BUFFER +(defun ido-kill-buffer-at-head () + "Kill the buffer at the head of `ido-matches'. +If cursor is not at the end of the user input, delete to end of input." + (interactive) + (if (not (eobp)) + (delete-region (point) (line-end-position)) + (let ((enable-recursive-minibuffers t) + (buf (ido-name (car ido-matches))) + (nextbuf (cadr ido-matches))) + (when (get-buffer buf) + ;; If next match names a buffer use the buffer object; buffer + ;; name may be changed by packages such as uniquify; mindful + ;; of virtual buffers. + (when (and nextbuf (get-buffer nextbuf)) + (setq nextbuf (get-buffer nextbuf))) + (if (null (kill-buffer buf)) + ;; Buffer couldn't be killed. + (setq ido-rescan t) + ;; Else `kill-buffer' succeeds so re-make the buffer list + ;; taking into account packages like uniquify may rename + ;; buffers. + (if (bufferp nextbuf) + (setq nextbuf (buffer-name nextbuf))) + (setq ido-default-item nextbuf + ido-text-init ido-text + ido-exit 'refresh) + (exit-minibuffer)))))) + +;;; DELETE CURRENT FILE +(defun ido-delete-file-at-head () + "Delete the file at the head of `ido-matches'. +If cursor is not at the end of the user input, delete to end of input." + (interactive) + (if (not (eobp)) + (delete-region (point) (line-end-position)) + (let ((enable-recursive-minibuffers t) + (file (ido-name (car ido-matches)))) + (if file + (setq file (concat ido-current-directory file))) + (when (and file + (file-exists-p file) + (not (file-directory-p file)) + (file-writable-p ido-current-directory) + (yes-or-no-p (concat "Delete " file "? "))) + (delete-file file) + ;; Check if file still exists. + (if (file-exists-p file) + ;; file could not be deleted + (setq ido-rescan t) + ;; else file was killed so remove name from list. + (setq ido-cur-list (delq (car ido-matches) ido-cur-list))))))) + + +;;; VISIT CHOSEN BUFFER +(defun ido-visit-buffer (buffer method &optional record) + "Switch to BUFFER according to METHOD. +Record command in `command-history' if optional RECORD is non-nil." + (if (bufferp buffer) + (setq buffer (buffer-name buffer))) + (let (win newframe) + (cond + ((eq method 'kill) + (if record + (ido-record-command 'kill-buffer buffer)) + (kill-buffer buffer)) + + ((eq method 'other-window) + (if record + (ido-record-command 'switch-to-buffer buffer)) + (switch-to-buffer-other-window buffer)) + + ((eq method 'display) + (display-buffer buffer)) + + ((eq method 'other-frame) + (switch-to-buffer-other-frame buffer) + (select-frame-set-input-focus (selected-frame))) + + ((and (memq method '(raise-frame maybe-frame)) + window-system + (setq win (ido-buffer-window-other-frame buffer)) + (or (eq method 'raise-frame) + (y-or-n-p "Jump to frame? "))) + (setq newframe (window-frame win)) + (select-frame-set-input-focus newframe) + (select-window win)) + + ;; (eq method 'selected-window) + (t + ;; No buffer in other frames... + (if record + (ido-record-command 'switch-to-buffer buffer)) + (switch-to-buffer buffer) + )))) + + +(defun ido-buffer-window-other-frame (buffer) + ;; Return window pointer if BUFFER is visible in another frame. + ;; If BUFFER is visible in the current frame, return nil. + (let ((blist (ido-get-buffers-in-frames 'current))) + ;;If the buffer is visible in current frame, return nil + (if (member buffer blist) + nil + ;; maybe in other frame or icon + (get-buffer-window buffer 0) ; better than 'visible + ))) + + +;;; ----------- IDONIZED FUNCTIONS ------------ + +;;;###autoload +(defun ido-switch-buffer () + "Switch to another buffer. +The buffer is displayed according to `ido-default-buffer-method' -- the +default is to show it in the same window, unless it is already visible +in another frame. + +As you type in a string, all of the buffers matching the string are +displayed if substring-matching is used \(default). Look at +`ido-enable-prefix' and `ido-toggle-prefix'. When you have found the +buffer you want, it can then be selected. As you type, most keys have +their normal keybindings, except for the following: \\ + +RET Select the buffer at the front of the list of matches. If the +list is empty, possibly prompt to create new buffer. + +\\[ido-select-text] Select the current prompt as the buffer. +If no buffer is found, prompt for a new one. + +\\[ido-next-match] Put the first element at the end of the list. +\\[ido-prev-match] Put the last element at the start of the list. +\\[ido-complete] Complete a common suffix to the current string that +matches all buffers. If there is only one match, select that buffer. +If there is no common suffix, show a list of all matching buffers +in a separate window. +\\[ido-edit-input] Edit input string. +\\[ido-fallback-command] Fallback to non-ido version of current command. +\\[ido-toggle-regexp] Toggle regexp searching. +\\[ido-toggle-prefix] Toggle between substring and prefix matching. +\\[ido-toggle-case] Toggle case-sensitive searching of buffer names. +\\[ido-completion-help] Show list of matching buffers in separate window. +\\[ido-enter-find-file] Drop into `ido-find-file'. +\\[ido-kill-buffer-at-head] Kill buffer at head of buffer list. +\\[ido-toggle-ignore] Toggle ignoring buffers listed in `ido-ignore-buffers'." + (interactive) + (ido-buffer-internal ido-default-buffer-method)) + +;;;###autoload +(defun ido-switch-buffer-other-window () + "Switch to another buffer and show it in another window. +The buffer name is selected interactively by typing a substring. +For details of keybindings, see `ido-switch-buffer'." + (interactive) + (ido-buffer-internal 'other-window 'switch-to-buffer-other-window)) + +;;;###autoload +(defun ido-display-buffer () + "Display a buffer in another window but don't select it. +The buffer name is selected interactively by typing a substring. +For details of keybindings, see `ido-switch-buffer'." + (interactive) + (ido-buffer-internal 'display 'display-buffer nil nil nil 'ignore)) + +;;;###autoload +(defun ido-kill-buffer () + "Kill a buffer. +The buffer name is selected interactively by typing a substring. +For details of keybindings, see `ido-switch-buffer'." + (interactive) + (ido-buffer-internal 'kill 'kill-buffer "Kill buffer: " (buffer-name (current-buffer)) nil 'ignore)) + +;;;###autoload +(defun ido-insert-buffer () + "Insert contents of a buffer in current buffer after point. +The buffer name is selected interactively by typing a substring. +For details of keybindings, see `ido-switch-buffer'." + (interactive) + (ido-buffer-internal 'insert 'insert-buffer "Insert buffer: " nil nil 'ido-enter-insert-file)) + +;;;###autoload +(defun ido-switch-buffer-other-frame () + "Switch to another buffer and show it in another frame. +The buffer name is selected interactively by typing a substring. +For details of keybindings, see `ido-switch-buffer'." + (interactive) + (if ido-mode + (ido-buffer-internal 'other-frame) + (call-interactively 'switch-to-buffer-other-frame))) + +;;;###autoload +(defun ido-find-file-in-dir (dir) + "Switch to another file starting from DIR." + (interactive "DDir: ") + (setq dir (file-name-as-directory dir)) + (ido-file-internal ido-default-file-method nil dir nil nil nil 'ignore)) + +;;;###autoload +(defun ido-find-file () + "Edit file with name obtained via minibuffer. +The file is displayed according to `ido-default-file-method' -- the +default is to show it in the same window, unless it is already +visible in another frame. + +The file name is selected interactively by typing a substring. As you +type in a string, all of the filenames matching the string are displayed +if substring-matching is used \(default). Look at `ido-enable-prefix' and +`ido-toggle-prefix'. When you have found the filename you want, it can +then be selected. As you type, most keys have their normal keybindings, +except for the following: \\ + +RET Select the file at the front of the list of matches. If the +list is empty, possibly prompt to create new file. + +\\[ido-select-text] Select the current prompt as the buffer or file. +If no buffer or file is found, prompt for a new one. + +\\[ido-next-match] Put the first element at the end of the list. +\\[ido-prev-match] Put the last element at the start of the list. +\\[ido-complete] Complete a common suffix to the current string that +matches all files. If there is only one match, select that file. +If there is no common suffix, show a list of all matching files +in a separate window. +\\[ido-edit-input] Edit input string (including directory). +\\[ido-prev-work-directory] or \\[ido-next-work-directory] go to previous/next directory in work directory history. +\\[ido-merge-work-directories] search for file in the work directory history. +\\[ido-forget-work-directory] removes current directory from the work directory history. +\\[ido-prev-work-file] or \\[ido-next-work-file] cycle through the work file history. +\\[ido-wide-find-file-or-pop-dir] and \\[ido-wide-find-dir-or-delete-dir] prompts and uses find to locate files or directories. +\\[ido-make-directory] prompts for a directory to create in current directory. +\\[ido-fallback-command] Fallback to non-ido version of current command. +\\[ido-toggle-regexp] Toggle regexp searching. +\\[ido-toggle-prefix] Toggle between substring and prefix matching. +\\[ido-toggle-case] Toggle case-sensitive searching of file names. +\\[ido-toggle-vc] Toggle version control for this file. +\\[ido-toggle-literal] Toggle literal reading of this file. +\\[ido-completion-help] Show list of matching files in separate window. +\\[ido-toggle-ignore] Toggle ignoring files listed in `ido-ignore-files'." + + (interactive) + (ido-file-internal ido-default-file-method)) + +;;;###autoload +(defun ido-find-file-other-window () + "Switch to another file and show it in another window. +The file name is selected interactively by typing a substring. +For details of keybindings, see `ido-find-file'." + (interactive) + (ido-file-internal 'other-window 'find-file-other-window)) + +;;;###autoload +(defun ido-find-alternate-file () + "Switch to another file and show it in another window. +The file name is selected interactively by typing a substring. +For details of keybindings, see `ido-find-file'." + (interactive) + (ido-file-internal 'alt-file 'find-alternate-file nil "Find alternate file: ")) + +;;;###autoload +(defun ido-find-file-read-only () + "Edit file read-only with name obtained via minibuffer. +The file name is selected interactively by typing a substring. +For details of keybindings, see `ido-find-file'." + (interactive) + (ido-file-internal 'read-only 'find-file-read-only nil "Find file read-only: ")) + +;;;###autoload +(defun ido-find-file-read-only-other-window () + "Edit file read-only in other window with name obtained via minibuffer. +The file name is selected interactively by typing a substring. +For details of keybindings, see `ido-find-file'." + (interactive) + (ido-file-internal 'read-only 'find-file-read-only-other-window nil "Find file read-only other window: ")) + +;;;###autoload +(defun ido-find-file-read-only-other-frame () + "Edit file read-only in other frame with name obtained via minibuffer. +The file name is selected interactively by typing a substring. +For details of keybindings, see `ido-find-file'." + (interactive) + (ido-file-internal 'read-only 'find-file-read-only-other-frame nil "Find file read-only other frame: ")) + +;;;###autoload +(defun ido-display-file () + "Display a file in another window but don't select it. +The file name is selected interactively by typing a substring. +For details of keybindings, see `ido-find-file'." + (interactive) + (ido-file-internal 'display nil nil nil nil nil 'ignore)) + +;;;###autoload +(defun ido-find-file-other-frame () + "Switch to another file and show it in another frame. +The file name is selected interactively by typing a substring. +For details of keybindings, see `ido-find-file'." + (interactive) + (ido-file-internal 'other-frame 'find-file-other-frame)) + +;;;###autoload +(defun ido-write-file () + "Write current buffer to a file. +The file name is selected interactively by typing a substring. +For details of keybindings, see `ido-find-file'." + (interactive) + (let ((ido-process-ignore-lists t) + (ido-work-directory-match-only nil) + (ido-ignore-files (cons "[^/]\\'" ido-ignore-files)) + (ido-report-no-match nil) + (ido-confirm-unique-completion t) + (ido-auto-merge-work-directories-length -1)) + (ido-file-internal 'write 'write-file nil "Write file: " nil nil 'ignore))) + +;;;###autoload +(defun ido-insert-file () + "Insert contents of file in current buffer. +The file name is selected interactively by typing a substring. +For details of keybindings, see `ido-find-file'." + (interactive) + (ido-file-internal 'insert 'insert-file nil "Insert file: " nil nil 'ido-enter-insert-buffer)) + +;;;###autoload +(defun ido-dired () + "Call `dired' the ido way. +The directory is selected interactively by typing a substring. +For details of keybindings, see `ido-find-file'." + (interactive) + (let ((ido-report-no-match nil) + (ido-auto-merge-work-directories-length -1)) + (ido-file-internal 'dired 'dired nil "Dired: " 'dir))) + +(defun ido-list-directory () + "Call `list-directory' the ido way. +The directory is selected interactively by typing a substring. +For details of keybindings, see `ido-find-file'." + (interactive) + (let ((ido-report-no-match nil) + (ido-auto-merge-work-directories-length -1)) + (ido-file-internal 'list-directory 'list-directory nil "List directory: " 'dir))) + +;;; XEmacs hack for showing default buffer + +;; The first time we enter the minibuffer, Emacs puts up the default +;; buffer to switch to, but XEmacs doesn't -- presumably there is a +;; subtle difference in the two versions of post-command-hook. The +;; default is shown for both whenever we delete all of our text +;; though, indicating its just a problem the first time we enter the +;; function. To solve this, we use another entry hook for emacs to +;; show the default the first time we enter the minibuffer. + + +;;; ICOMPLETE TYPE CODE + +(defun ido-initiate-auto-merge (buffer) + (ido-trace "\n*merge timeout*" buffer) + (setq ido-auto-merge-timer nil) + (when (and (buffer-live-p buffer) + (ido-active) + (boundp 'ido-eoinput) ido-eoinput) + (let ((contents (buffer-substring-no-properties (minibuffer-prompt-end) ido-eoinput))) + (ido-trace "request merge") + (setq ido-use-merged-list 'auto + ido-text-init contents + ido-rotate-temp t + ido-exit 'refresh) + (with-current-buffer buffer + (ido-tidy)) + (throw 'ido contents)))) + +(defun ido-exhibit () + "Post command hook for `ido'." + ;; Find matching files and display a list in the minibuffer. + ;; Copied from `icomplete-exhibit' with two changes: + ;; 1. It prints a default file name when there is no text yet entered. + ;; 2. It calls my completion routine rather than the standard completion. + + (when (ido-active) + (let ((contents (buffer-substring-no-properties (minibuffer-prompt-end) (point-max))) + (buffer-undo-list t) + try-single-dir-match + refresh) + + (when ido-trace-enable + (ido-trace "\nexhibit" this-command) + (ido-trace "dir" ido-current-directory) + (ido-trace "contents" contents) + (ido-trace "list" ido-cur-list) + (ido-trace "matches" ido-matches) + (ido-trace "rescan" ido-rescan)) + + (save-excursion + (goto-char (point-max)) + ;; Register the end of input, so we know where the extra stuff (match-status info) begins: + (unless (boundp 'ido-eoinput) + ;; In case it got wiped out by major mode business: + (make-local-variable 'ido-eoinput)) + (setq ido-eoinput (point)) + + ;; Handle explicit directory changes + (cond + ((memq ido-cur-item '(buffer list)) + ) + + ((= (length contents) 0) + ) + + ((= (length contents) 1) + (cond + ((and (ido-is-tramp-root) (string-equal contents "/")) + (ido-set-current-directory ido-current-directory contents) + (setq refresh t)) + ((and (ido-unc-hosts) (string-equal contents "/") + (let ((ido-enable-tramp-completion nil)) + (ido-is-root-directory))) + (ido-set-current-directory "//") + (setq refresh t)) + )) + + ((and (string-match (if ido-enable-tramp-completion ".[:@]\\'" ".:\\'") contents) + (ido-is-root-directory) ;; Ange-ftp or tramp + (not (ido-local-file-exists-p contents))) + (ido-set-current-directory ido-current-directory contents) + (when (ido-is-slow-ftp-host) + (setq ido-exit 'fallback) + (exit-minibuffer)) + (setq refresh t)) + + ((ido-final-slash contents) ;; xxx/ + (ido-trace "final slash" contents) + (cond + ((string-equal contents "~/") + (ido-set-current-home) + (setq refresh t)) + ((string-equal contents "../") + (ido-up-directory t) + (setq refresh t)) + ((string-equal contents "./") + (setq refresh t)) + ((string-match "\\`~[-_a-zA-Z0-9]+[$]?/\\'" contents) + (ido-trace "new home" contents) + (ido-set-current-home contents) + (setq refresh t)) + ((string-match "[$][A-Za-z0-9_]+/\\'" contents) + (let ((exp (condition-case () + (expand-file-name + (substitute-in-file-name (substring contents 0 -1)) + ido-current-directory) + (error nil)))) + (ido-trace contents exp) + (when (and exp (file-directory-p exp)) + (ido-set-current-directory (file-name-directory exp)) + (setq ido-text-init (file-name-nondirectory exp)) + (setq refresh t)))) + ((and (memq system-type '(windows-nt ms-dos)) + (string-equal (substring contents 1) ":/")) + (ido-set-current-directory (file-name-directory contents)) + (setq refresh t)) + ((string-equal (substring contents -2 -1) "/") + (ido-set-current-directory + (if (memq system-type '(windows-nt ms-dos)) + (expand-file-name "/" ido-current-directory) + "/")) + (setq refresh t)) + ((and (or ido-directory-nonreadable ido-directory-too-big) + (file-directory-p (concat ido-current-directory (file-name-directory contents)))) + (ido-set-current-directory + (concat ido-current-directory (file-name-directory contents))) + (setq refresh t)) + (t + (ido-trace "try single dir") + (setq try-single-dir-match t)))) + + ((and (string-equal (substring contents -2 -1) "/") + (not (string-match "[$]" contents))) + (ido-set-current-directory + (cond + ((= (length contents) 2) + "/") + (ido-matches + (concat ido-current-directory (ido-name (car ido-matches)))) + (t + (concat ido-current-directory (substring contents 0 -1))))) + (setq ido-text-init (substring contents -1)) + (setq refresh t)) + + ((and (not ido-use-merged-list) + (not (ido-final-slash contents)) + (eq ido-try-merged-list t) + (numberp ido-auto-merge-work-directories-length) + (> ido-auto-merge-work-directories-length 0) + (= (length contents) ido-auto-merge-work-directories-length) + (not (and ido-auto-merge-inhibit-characters-regexp + (string-match ido-auto-merge-inhibit-characters-regexp contents))) + (not (input-pending-p))) + (setq ido-use-merged-list 'auto + ido-text-init contents + ido-rotate-temp t) + (setq refresh t)) + + (t nil)) + + (when refresh + (ido-trace "refresh on /" ido-text-init) + (setq ido-exit 'refresh) + (exit-minibuffer)) + + ;; Update the list of matches + (setq ido-text contents) + (ido-set-matches) + (ido-trace "new " ido-matches) + + (when (and ido-enter-matching-directory + ido-matches + (or (eq ido-enter-matching-directory 'first) + (null (cdr ido-matches))) + (ido-final-slash (ido-name (car ido-matches))) + (or try-single-dir-match + (eq ido-enter-matching-directory t))) + (ido-trace "single match" (car ido-matches)) + (ido-set-current-directory + (concat ido-current-directory (ido-name (car ido-matches)))) + (setq ido-exit 'refresh) + (exit-minibuffer)) + + (when (and (not ido-matches) + (not ido-directory-nonreadable) + (not ido-directory-too-big) + ;; ido-rescan ? + ido-process-ignore-lists + ido-ignored-list) + (let ((ido-process-ignore-lists nil) + (ido-rotate ido-rotate) + (ido-cur-list ido-ignored-list)) + (ido-trace "try all" ido-ignored-list) + (ido-set-matches)) + (when ido-matches + (ido-trace "found " ido-matches) + (setq ido-rescan t) + (setq ido-process-ignore-lists-inhibit t) + (setq ido-text-init ido-text) + (setq ido-exit 'refresh) + (exit-minibuffer))) + + (when (and + ido-rescan + (not ido-matches) + (memq ido-cur-item '(file dir)) + (not (ido-is-root-directory)) + (> (length contents) 1) + (not (string-match "[$]" contents)) + (not ido-directory-nonreadable) + (not ido-directory-too-big)) + (ido-trace "merge?") + (if ido-use-merged-list + (ido-undo-merge-work-directory contents nil) + (when (and (eq ido-try-merged-list t) + (numberp ido-auto-merge-work-directories-length) + (= ido-auto-merge-work-directories-length 0) + (not (and ido-auto-merge-inhibit-characters-regexp + (string-match ido-auto-merge-inhibit-characters-regexp contents))) + (not (input-pending-p))) + (ido-trace "\n*start timer*") + (setq ido-auto-merge-timer + (run-with-timer ido-auto-merge-delay-time nil 'ido-initiate-auto-merge (current-buffer)))))) + + (setq ido-rescan t) + + (if (and ido-use-merged-list + ido-matches + (not (string-equal (car (cdr (car ido-matches))) ido-current-directory))) + (progn + (ido-set-current-directory (car (cdr (car ido-matches)))) + (setq ido-use-merged-list t + ido-exit 'keep + ido-text-init ido-text) + (exit-minibuffer))) + + ;; Insert the match-status information: + (ido-set-common-completion) + (let ((inf (ido-completions contents))) + (setq ido-show-confirm-message nil) + (ido-trace "inf" inf) + (insert inf)) + )))) + +(defun ido-completions (name) + ;; Return the string that is displayed after the user's text. + ;; Modified from `icomplete-completions'. + + (let* ((comps ido-matches) + (ind (and (consp (car comps)) (> (length (cdr (car comps))) 1) + ido-merged-indicator)) + first) + + (if (and ind ido-use-faces) + (put-text-property 0 1 'face 'ido-indicator ind)) + + (if (and ido-use-faces comps) + (let* ((fn (ido-name (car comps))) + (ln (length fn))) + (setq first (format "%s" fn)) + (put-text-property 0 ln 'face + (if (= (length comps) 1) + (if ido-incomplete-regexp + 'ido-incomplete-regexp + 'ido-only-match) + 'ido-first-match) + first) + (if ind (setq first (concat first ind))) + (setq comps (cons first (cdr comps))))) + + (cond ((null comps) + (cond + (ido-show-confirm-message + (or (nth 10 ido-decorations) " [Confirm]")) + (ido-directory-nonreadable + (or (nth 8 ido-decorations) " [Not readable]")) + (ido-directory-too-big + (or (nth 9 ido-decorations) " [Too big]")) + (ido-report-no-match + (nth 6 ido-decorations)) ;; [No match] + (t ""))) + (ido-incomplete-regexp + (concat " " (car comps))) + ((null (cdr comps)) ;one match + (concat (if (if (not ido-enable-regexp) + (= (length (ido-name (car comps))) (length name)) + ;; We can't rely on the length of the input + ;; for regexps, so explicitly check for a + ;; complete match + (string-match name (ido-name (car comps))) + (string-equal (match-string 0 (ido-name (car comps))) + (ido-name (car comps)))) + "" + ;; when there is one match, show the matching file name in full + (concat (nth 4 ido-decorations) ;; [ ... ] + (ido-name (car comps)) + (nth 5 ido-decorations))) + (if (not ido-use-faces) (nth 7 ido-decorations)))) ;; [Matched] + (t ;multiple matches + (let* ((items (if (> ido-max-prospects 0) (1+ ido-max-prospects) 999)) + (alternatives + (apply + #'concat + (cdr (apply + #'nconc + (mapcar + (lambda (com) + (setq com (ido-name com)) + (setq items (1- items)) + (cond + ((< items 0) ()) + ((= items 0) (list (nth 3 ido-decorations))) ; " | ..." + (t + (list (or ido-separator (nth 2 ido-decorations)) ; " | " + (let ((str (substring com 0))) + (if (and ido-use-faces + (not (string= str first)) + (ido-final-slash str)) + (put-text-property 0 (length str) 'face 'ido-subdir str)) + str))))) + comps)))))) + + (concat + ;; put in common completion item -- what you get by pressing tab + (if (and (stringp ido-common-match-string) + (> (length ido-common-match-string) (length name))) + (concat (nth 4 ido-decorations) ;; [ ... ] + (substring ido-common-match-string (length name)) + (nth 5 ido-decorations))) + ;; list all alternatives + (nth 0 ido-decorations) ;; { ... } + alternatives + (nth 1 ido-decorations))))))) + +(defun ido-minibuffer-setup () + "Minibuffer setup hook for `ido'." + ;; Copied from `icomplete-minibuffer-setup-hook'. + (when (ido-active) + (add-hook 'pre-command-hook 'ido-tidy nil t) + (add-hook 'post-command-hook 'ido-exhibit nil t) + (when (featurep 'xemacs) + (ido-exhibit) + (goto-char (point-min))) + (run-hooks 'ido-minibuffer-setup-hook) + (when ido-initial-position + (goto-char (+ (minibuffer-prompt-end) ido-initial-position)) + (setq ido-initial-position nil)))) + +(defun ido-tidy () + "Pre command hook for `ido'." + ;; Remove completions display, if any, prior to new user input. + ;; Copied from `icomplete-tidy'." + + (when ido-auto-merge-timer + (ido-trace "\n*cancel timer*" this-command) + (cancel-timer ido-auto-merge-timer) + (setq ido-auto-merge-timer nil)) + + (if (ido-active) + (if (and (boundp 'ido-eoinput) + ido-eoinput) + + (if (> ido-eoinput (point-max)) + ;; Oops, got rug pulled out from under us - reinit: + (setq ido-eoinput (point-max)) + (let ((buffer-undo-list t)) + (delete-region ido-eoinput (point-max)))) + + ;; Reestablish the local variable 'cause minibuffer-setup is weird: + (make-local-variable 'ido-eoinput) + (setq ido-eoinput 1)))) + +(defun ido-summary-buffers-to-end () + ;; Move the summaries to the end of the buffer list. + ;; This is an example function which can be hooked on to + ;; `ido-make-buffer-list-hook'. Any buffer matching the regexps + ;; `Summary' or `output\*$'are put to the end of the list. + (let ((summaries (delq nil (mapcar + (lambda (x) + (if (or + (string-match "Summary" x) + (string-match "output\\*\\'" x)) + x)) + ido-temp-list)))) + (ido-to-end summaries))) + +;;; Helper functions for other programs + +(put 'dired-do-rename 'ido 'ignore) +(put 'ibuffer-find-file 'ido 'find-file) +(put 'dired-other-window 'ido 'dir) + +;;;###autoload +(defun ido-read-buffer (prompt &optional default require-match) + "Ido replacement for the built-in `read-buffer'. +Return the name of a buffer selected. +PROMPT is the prompt to give to the user. DEFAULT if given is the default +buffer to be selected, which will go to the front of the list. +If REQUIRE-MATCH is non-nil, an existing buffer must be selected." + (let* ((ido-current-directory nil) + (ido-directory-nonreadable nil) + (ido-directory-too-big nil) + (ido-context-switch-command 'ignore) + (buf (ido-read-internal 'buffer prompt 'ido-buffer-history default require-match))) + (if (eq ido-exit 'fallback) + (let ((read-buffer-function nil)) + (run-hook-with-args 'ido-before-fallback-functions 'read-buffer) + (read-buffer prompt default require-match)) + buf))) + +;;;###autoload +(defun ido-read-file-name (prompt &optional dir default-filename mustmatch initial predicate) + "Ido replacement for the built-in `read-file-name'. +Read file name, prompting with PROMPT and completing in directory DIR. +See `read-file-name' for additional parameters." + (let (filename) + (cond + ((or (eq predicate 'file-directory-p) + (eq (get this-command 'ido) 'dir) + (memq this-command ido-read-file-name-as-directory-commands)) + (setq filename + (ido-read-directory-name prompt dir default-filename mustmatch initial)) + (if (eq ido-exit 'fallback) + (setq filename 'fallback))) + ((and (not (eq (get this-command 'ido) 'ignore)) + (not (memq this-command ido-read-file-name-non-ido)) + (or (null predicate) (eq predicate 'file-exists-p))) + (let* (ido-saved-vc-hb + (ido-context-switch-command + (if (eq (get this-command 'ido) 'find-file) nil 'ignore)) + (vc-handled-backends (and (boundp 'vc-handled-backends) vc-handled-backends)) + (minibuffer-completing-file-name t) + (ido-current-directory (ido-expand-directory dir)) + (ido-directory-nonreadable (not (file-readable-p ido-current-directory))) + (ido-directory-too-big (and (not ido-directory-nonreadable) + (ido-directory-too-big-p ido-current-directory))) + (ido-work-directory-index -1) + (ido-show-dot-for-dired (and ido-show-dot-for-dired + (not default-filename))) + (ido-work-file-index -1) + (ido-find-literal nil)) + (setq ido-exit nil) + (setq filename + (ido-read-internal 'file prompt 'ido-file-history default-filename mustmatch initial)) + (cond + ((eq ido-exit 'fallback) + (setq filename 'fallback)) + ((eq ido-exit 'dired) + (setq filename ido-current-directory)) + (filename + (setq filename + (concat ido-current-directory filename)))))) + (t + (setq filename 'fallback))) + (if (eq filename 'fallback) + (let ((read-file-name-function nil)) + (run-hook-with-args 'ido-before-fallback-functions 'read-file-name) + (read-file-name prompt dir default-filename mustmatch initial predicate)) + filename))) + +;;;###autoload +(defun ido-read-directory-name (prompt &optional dir default-dirname mustmatch initial) + "Ido replacement for the built-in `read-directory-name'. +Read directory name, prompting with PROMPT and completing in directory DIR. +See `read-directory-name' for additional parameters." + (let* (filename + (minibuffer-completing-file-name t) + (ido-context-switch-command 'ignore) + ido-saved-vc-hb + (ido-current-directory (ido-expand-directory dir)) + (ido-directory-nonreadable (not (file-readable-p ido-current-directory))) + (ido-directory-too-big (and (not ido-directory-nonreadable) + (ido-directory-too-big-p ido-current-directory))) + (ido-work-directory-index -1) + (ido-work-file-index -1)) + (setq filename + (ido-read-internal 'dir prompt 'ido-file-history default-dirname mustmatch initial)) + (if filename + (if (and (stringp filename) (string-equal filename ".")) + ido-current-directory + (concat ido-current-directory filename))))) + +;;;###autoload +(defun ido-completing-read (prompt choices &optional predicate require-match initial-input hist def inherit-input-method) + "Ido replacement for the built-in `completing-read'. +Read a string in the minibuffer with ido-style completion. +PROMPT is a string to prompt with; normally it ends in a colon and a space. +CHOICES is a list of strings which are the possible completions. +PREDICATE and INHERIT-INPUT-METHOD is currently ignored; it is included + to be compatible with `completing-read'. +If REQUIRE-MATCH is non-nil, the user is not allowed to exit unless + the input is (or completes to) an element of CHOICES or is null. + If the input is null, `ido-completing-read' returns DEF, or an empty + string if DEF is nil, regardless of the value of REQUIRE-MATCH. +If INITIAL-INPUT is non-nil, insert it in the minibuffer initially, + with point positioned at the end. +HIST, if non-nil, specifies a history list. +DEF, if non-nil, is the default value." + (let ((ido-current-directory nil) + (ido-directory-nonreadable nil) + (ido-directory-too-big nil) + (ido-context-switch-command 'ignore) + (ido-choice-list choices)) + ;; Initialize ido before invoking ido-read-internal + (ido-common-initialization) + (ido-read-internal 'list prompt hist def require-match initial-input))) + +(defun ido-unload-function () + "Unload the Ido library." + (ido-mode -1) + (setq minor-mode-map-alist (assq-delete-all 'ido-mode minor-mode-map-alist)) + ;; continue standard unloading + nil) + +(provide 'ido) + +;;; ido.el ends here diff --git a/lisp/imenu+.el b/lisp/imenu+.el new file mode 100644 index 0000000..3f5b6d2 --- /dev/null +++ b/lisp/imenu+.el @@ -0,0 +1,580 @@ +;;; imenu+.el --- Extensions to `imenu.el'. +;; +;; Filename: imenu+.el +;; Description: Extensions to `imenu.el'. +;; Author: Drew Adams +;; Maintainer: Drew Adams +;; Copyright (C) 1999-2012, Drew Adams, all rights reserved. +;; Created: Thu Aug 26 16:05:01 1999 +;; Version: 21.0 +;; Last-Updated: Sun Jan 1 16:24:16 2012 (-0800) +;; By: dradams +;; Update #: 725 +;; URL: http://www.emacswiki.org/cgi-bin/wiki/imenu+.el +;; Keywords: tools, menus +;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x +;; +;; Features that might be required by this library: +;; +;; `imenu'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Extensions to `imenu.el'. +;; +;; New functions defined here: +;; +;; `imenu-add-defs-to-menubar', `imenu--sort-submenu', +;; `imenup-invisible-p', `toggle-imenu-sort'. +;; +;; New user options (variables) defined here: +;; +;; `emacs-lisp-imenu-generic-expression', +;; `imenu-emacs-face-defn-regexp', `imenu-emacs-key-defn-regexp-1', +;; `imenu-emacs-key-defn-regexp-2', +;; `imenu-emacs-option-defn-regexp', `imenu-lisp-fn-defn-regexp', +;; `imenu-lisp-macro-defn-regexp', `imenu-lisp-other-defn-regexp', +;; `imenu-lisp-var-defn-regexp', `imenu-sort-function'. +;; +;; Other variables defined here: +;; +;; `imenu-last-sort-function'. +;; +;; +;; ***** NOTE: The following functions and macro defined in `imenu.el' +;; have been REDEFINED HERE: +;; +;; `imenu--generic-function', `imenu--make-index-alist' (Emacs +;; 21+), `imenu--mouse-menu', `imenu-progress-message', +;; `imenu-update-menubar' (Emacs <22). +;; +;; +;; ***** NOTE: The following variable defined in `imenu.el' has +;; been REDEFINED HERE: +;; +;; `imenu-sort-function'. +;; +;; ***** NOTE: The following variable defined in `lisp-mode.el' has +;; been REDEFINED HERE: +;; +;; `lisp-imenu-generic-expression'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change Log: +;; +;; 2012/01/01 dadams +;; imenu-update-menubar: buffer-modified-tick -> buffer-chars-modified-tick. (Sync w/ vanilla.) +;; 2011/11/24 dadams +;; Added: imenup-invisible-p. +;; imenu--generic-function: Use imenup-invisible-p, not just get-text-property (so overlays too). +;; 2011/11/23 dadams +;; Make menu ignore invisible text and respect ignore-comments-flag. Added (redefinition of): +;; imenu--make-index-alist, imenu--generic-function, imenu-progress-message. +;; 2001/08/26 dadams +;; imenu--sort-submenu: Copy MENU-ITEMS so sort doesn't modify it. Thx to Michael Heerdegen. +;; 2011/05/27 dadams +;; imenu-lisp-var-defn-regexp: +;; Corrected to allow \n after var name (\n is comment-end syntax, not whitespace, in Lisp). +;; 2011/05/08 dadams +;; imenu-lisp-var-defn-regexp: Try not to create entries for vacuous defvars, e.g., (defvar foo). +;; 2011/03/18 dadams +;; imenu-emacs-key-defn-regexp-[1|2]: Handle (kbd "..."). +;; emacs-lisp-imenu-generic-expression: Increased index from 4 to 5, to fit change for kbd. +;; 2011/01/04 dadams +;; Removed autoload cookies from defvar, non-interactive fns. Added for command. +;; 2007/01/16 dadams +;; imenu-lisp-fn-defn-regexp: Updated for icicle-define-add-to-alist-command. +;; 2005/12/09 dadams +;; imenu-lisp-fn-defn-regexp: Updated to include icicle-define*. +;; Use regexp-opt for Emacs 20 version too. +;; Moved Emacs 22 macro stuff to imenu-lisp-macro-defn-regexp. +;; (emacs-)lisp-imenu-generic-expression: +;; Updated Emacs 20 index to accomodate parens for icicle-define*. +;; Added: imenu-emacs-(face|option)-defn-regexp, +;; Removed: imenu-lisp-struct-defn-regexp. +;; Renamed: imenu-lisp-type-defn-regexp to imenu-lisp-other-defn-regexp. +;; 2005/05/17 dadams +;; Updated to work with Emacs 22.x. +;; 2004/11/21 dadams +;; imenu-lisp-type-defn-regexp, imenu-lisp-fn-defn-regexp, +;; imenu-lisp-var-defn-regexp: Got rid of purecopy & eval-when-compile. +;; 2004/11/20 dadams +;; Refined to deal with Emacs 21 < 21.3.50 (soon to be 22.x) +;; 2004/10/12 dadams +;; Updated for Emacs 21. +;; 2001/01/05 dadams +;; Unquoted mapcar lambda args. +;; 2000/11/01 dadams +;; Put imenu-add-defs-to-menubar inside condition-case, in (*-)lisp-mode-hooks +;; 1999/08/30 dadams +;; 1. imenu-emacs-key-defn-regexp-2: Added define-key-after. +;; 2. Updated emacs-lisp-imenu-generic-expression (Keys in Maps). +;; 1999/08/27 dadams +;; 1. Corrected: imenu-lisp-fn-defn-regexp, imenu-lisp-macro-defn-regexp, +;; imenu-lisp-var-defn-regexp, imenu--sort-submenu, +;; imenu-emacs-key-defn-regexp-2. +;; 2. Added: imenu--sort-submenu, imenu-update-menubar, imenu--mouse-menu. +;; Redefinition of originals: imenu-update-menubar, imenu--mouse-menu. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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, 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; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(and (< emacs-major-version 20) (eval-when-compile (require 'cl))) ;; cadr, when, unless + +(require 'imenu) + +;; Quiet the byte-compiler +(defvar imenu-menubar-modified-tick) + +;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; Customizable variables + +(defconst imenu-sort-function 'imenu--sort-by-name) + +;; For key definitions, we need to handle: strings and vectors, but also (kbd STRING). +;; We just match optional `(kbd ' followed by a string or a vector'. +(defvar imenu-emacs-key-defn-regexp-1 "(\\s-*\\(\\(global\\|local\\)-\\(un\\)?\ +set-key\\|undefine-keys-bound-to\\)\\s-*\\((kbd\\s-*\\)?\\(\"[^\"]+\"\\|[[][^]]+[]]\\)" + "*Regexp that recognizes Emacs key definitions. +See also `imenu-emacs-key-defn-regexp-2'.") + +(defvar imenu-emacs-key-defn-regexp-2 "(\\s-*\\(define-key\\(-after\\)?\\s-+\ +\\|substitute-key-definition\\s-+'\\)\\(\\S-+\\)\\s-*'?\\((kbd\\s-*\\)?\\(\"[^\"]+\"\\|[[][^]]+[]]\\)" + "*Regexp that recognizes Emacs key definitions. +See also `imenu-emacs-key-defn-regexp-1'.") + +(defvar imenu-lisp-other-defn-regexp + (if (>= emacs-major-version 22) + (concat "^\\s-*(" + (regexp-opt '("defgroup" "deftheme" "deftype" "defstruct" + "defclass" "define-condition" "define-widget" + "defpackage") t) + "\\s-+'?\\(\\sw\\(\\sw\\|\\s_\\)+\\)") + "(\\s-*def\\(type\\|class\\|ine-condition\\)\\s-+'?\\([^ \t()]+\\)") + "*Regexp that recognizes other Lisp definitions.") + +(defvar imenu-lisp-fn-defn-regexp + (if (>= emacs-major-version 22) + (concat "^\\s-*(" + (regexp-opt '("defun" "defun*" "defsubst" "defadvice" + "define-skeleton" "define-minor-mode" + "define-global-minor-mode" "define-globalized-minor-mode" + "define-derived-mode" "define-generic-mode" "defsetf" + "define-setf-expander" "define-method-combination" + "defgeneric" "defmethod" "icicle-define-command" + "icicle-define-file-command") t) + "\\s-+\\(\\sw\\(\\sw\\|\\s_\\)+\\)") + (concat "^\\s-*(" + (regexp-opt + '("defun" "defun*" "defsubst" "defadvice" "define-skeleton" + "define-derived-mode" "defsetf" "icicle-define-add-to-alist-command" + "icicle-define-command" "icicle-define-file-command") t) + "\\s-+\\(\\sw\\(\\sw\\|\\s_\\)+\\)")) + "*Regexp that recognizes Lisp function definitions.") + +(defvar imenu-lisp-macro-defn-regexp + "(\\s-*\\(defmacro\\|define-compiler-macro\\|define-modify-macro\\)\\s-+\\([^ \t()]+\\)" + "*Regexp that recognizes Lisp macro definitions.") + +(defvar imenu-emacs-face-defn-regexp "(\\s-*\\(defface\\)\\s-+\\([^ \t()]+\\)" + "*Regexp for Emacs face definitions (defface).") + +(defvar imenu-emacs-option-defn-regexp "(\\s-*\\(defcustom\\)\\s-+\\([^ \t()]+\\)" + "*Regexp for Emacs user option definitions (defcustom).") + +(defvar imenu-lisp-var-defn-regexp + (if (>= emacs-major-version 22) + (concat "^\\s-*(" + (regexp-opt '("defvar" "defconst" "defconstant" "defcustom" + "defparameter" "define-symbol-macro") t) + "\\s-+\\(\\sw\\(\\sw\\|\\s_\\)+\\)" + "\\(\\s-\\|[\n]\\)+" ; Because \n has char syntax `>', not whitespace. + "[^) \t\n]") + "(\\s-*def\\(var\\|const\\)\\s-+\\([^ \t()]+\\)") + "*Regexp that recognizes global Lisp variable definitions.") + + +;; REPLACE ORIGINAL in `lisp-mode.el'. +;; +;; Add `Functions', `Macros', `Structures'. +;; +(defconst lisp-imenu-generic-expression + (list + (list "Other" imenu-lisp-other-defn-regexp 2) + (list "Macros" imenu-lisp-macro-defn-regexp 2) + (list "Functions" imenu-lisp-fn-defn-regexp (if (string-match "\\(?:\\)" "") 2 6)) + (list "Variables" imenu-lisp-var-defn-regexp 2) + ) + "*Imenu generic expression for Lisp mode. +See `imenu-generic-expression'.") + +(defvar emacs-lisp-imenu-generic-expression + (list + (list "Other" imenu-lisp-other-defn-regexp 2) + (list "Keys in Maps" imenu-emacs-key-defn-regexp-2 5) + (list "Keys" imenu-emacs-key-defn-regexp-1 5) + (list "Macros" imenu-lisp-macro-defn-regexp 2) + (list "Functions" imenu-lisp-fn-defn-regexp (if (string-match "\\(?:\\)" "") 2 6)) + (list "Variables" imenu-lisp-var-defn-regexp 2) + (list "User Options" imenu-emacs-option-defn-regexp 2) + (list "Faces" imenu-emacs-face-defn-regexp 2) + ) + "*Imenu generic expression for Emacs Lisp mode. +See `imenu-generic-expression'.") + +(add-hook 'lisp-mode-hook + '(lambda () + (setq imenu-generic-expression lisp-imenu-generic-expression) + (condition-case nil + (imenu-add-defs-to-menubar) + (error nil)))) + +(add-hook 'emacs-lisp-mode-hook + '(lambda () + (setq imenu-generic-expression emacs-lisp-imenu-generic-expression) + (condition-case nil + (imenu-add-defs-to-menubar) + (error nil)))) + + +;;; Internal variables + +(defvar imenu-last-sort-function nil + "The last non-nil value for `imenu-sort-function' during this session.") + +;;;###autoload +(defalias 'toggle-imenu-sort 'imenu-toggle-sort) +;;;###autoload +(defun imenu-toggle-sort (force-p) + "Toggle imenu between sorting menus and not. +Non-nil prefix FORCE-P => Sort iff FORCE-P >= 0." + (interactive "P") + (cond (imenu-sort-function + (setq imenu-last-sort-function imenu-sort-function) ; Save it. + (when (or (null force-p) (<= (prefix-numeric-value force-p) 0)) + (setq imenu-sort-function nil))) ; Don't sort. + ((or (null force-p) (> (prefix-numeric-value force-p) 0)) ; Ask to sort + (if imenu-last-sort-function ; Sort using saved sort fn. + (setq imenu-sort-function imenu-last-sort-function) + (error "You first need to set `imenu-sort-function'")))) + (imenu--menubar-select imenu--rescan-item) + (if imenu-sort-function + (message "Imenus are now being sorted via `%s'." imenu-sort-function) + (message "Imenus are in buffer order (not sorted)."))) + +;;;###autoload +(defun imenu-add-defs-to-menubar () + "Add \"Defs\" imenu entry to menu bar for current local keymap. +See `imenu' for more information." + (interactive) + (imenu-add-to-menubar "Defs")) + +(defun imenu--sort-submenu (submenu predicate) + "Create an imenu SUBMENU, sorting with PREDICATE." + (let ((menu-name (car submenu)) + (menu-items (cdr submenu))) + (cons menu-name (if (and (consp menu-items) + (consp (cdr menu-items))) + ;; Must copy, because MENU-ITEMS can be part of `imenu--index-alist'. + (sort (copy-sequence menu-items) predicate) + menu-items)))) + + +;; REPLACE ORIGINAL in `imenu.el'. +;; +;; Sort each submenu before splitting submenus, instead of sorting among submenus after. +;; +(defun imenu-update-menubar () + "Update the Imenu menu. Use as `menu-bar-update-hook'." + (when (and (current-local-map) + (keymapp (lookup-key (current-local-map) [menu-bar index])) + (or (not (boundp 'imenu-menubar-modified-tick)) + (/= (buffer-chars-modified-tick) imenu-menubar-modified-tick))) ; Emacs 22+ + (when (boundp 'imenu-menubar-modified-tick) ; Emacs 22+ + (setq imenu-menubar-modified-tick (buffer-chars-modified-tick))) + (let ((index-alist (imenu--make-index-alist t))) + ;; Don't bother updating if the index-alist has not changed + ;; since the last time we did it. + (unless (equal index-alist imenu--last-menubar-index-alist) + (let (menu menu1 old) + (setq imenu--last-menubar-index-alist index-alist + index-alist (imenu--split-submenus + (if imenu-sort-function + (mapcar (lambda (sm) + (imenu--sort-submenu + sm imenu-sort-function)) + index-alist) + index-alist)) + menu (imenu--split-menu index-alist + (buffer-name))) + (if (>= emacs-major-version 22) + (setq menu1 (imenu--create-keymap (car menu) + (cdr (if (< 1 (length (cdr menu))) + menu + (car (cdr menu)))) + 'imenu--menubar-select)) + (setq menu1 (imenu--create-keymap-1 (car menu) + (if (< 1 (length (cdr menu))) + (cdr menu) + (cdr (car (cdr menu)))) + t))) + (setq old (lookup-key (current-local-map) [menu-bar index])) + (setcdr old (cdr menu1))))))) + + +(eval-and-compile + (when (< emacs-major-version 22) + + ;; REPLACE ORIGINAL in `imenu.el'. + ;; + ;; Use Emacs 22+ definition, which is vacuous. Otherwise, if byte-compile in Emacs < 22 and use + ;; the byte-compiled file in Emacs 22+, then get runtime error: + ;; `Error in menu-bar-update-hook: (void-variable imenu-scanning-message)'. + ;; + (defmacro imenu-progress-message (prevpos &optional relpos reverse) ))) + + +(eval-and-compile + (when (and (> emacs-major-version 20) (require 'hide-comnt nil t)) + + ;; REPLACE ORIGINAL in `imenu.el'. + ;; + ;; Respect `ignore-comments-flag', if defined: use `with-comments-hidden'. + ;; + (defun imenu--make-index-alist (&optional noerror) + "Create an index alist for the definitions in the current buffer. +This works by using the hook function `imenu-create-index-function'. +Report an error if the list is empty unless NOERROR is supplied and +non-nil. + +If `ignore-comments-flag' is defined and non-nil, then respect it, +ignoring hidden comments. + +See `imenu--index-alist' for the format of the index alist." + (or (and imenu--index-alist + (or (not imenu-auto-rescan) + (and imenu-auto-rescan (> (buffer-size) imenu-auto-rescan-maxout)))) + ;; Get the index; truncate if necessary + (progn (setq imenu--index-alist (save-excursion + (save-restriction + (widen) + (let ((search-invisible nil)) + (with-comments-hidden + (point-min) (point-max) + (funcall imenu-create-index-function)))))) + (imenu--truncate-items imenu--index-alist))) + (or imenu--index-alist noerror (error "No items suitable for an index found in this buffer")) + (or imenu--index-alist (setq imenu--index-alist (list nil))) + (cons imenu--rescan-item imenu--index-alist)))) ; Add `*Rescan*' to index. + +;; Same as `thgcmd-invisible-p' in `thing-cmds.el', and `icicle-invisible-p' in `icicles-cmd2.el'. +(defun imenup-invisible-p (position) + "Return non-nil if the character at POSITION is invisible." + (if (fboundp 'invisible-p) ; Emacs 22+ + (invisible-p position) + (let ((prop (get-char-property position 'invisible))) ; Overlay or text property. + (if (eq buffer-invisibility-spec t) + prop + (or (memq prop buffer-invisibility-spec) (assq prop buffer-invisibility-spec)))))) + + +;; REPLACE ORIGINAL in `imenu.el'. +;; +;; Ignore invisible definitions. +;; +(defun imenu--generic-function (patterns) + "Return an index alist of the current buffer based on PATTERNS. +PATTERNS is an alist with elements that look like this: + (MENU-TITLE REGEXP INDEX) +or like this: + (MENU-TITLE REGEXP INDEX FUNCTION ARGUMENTS...) +with zero or more ARGUMENTS. The former format creates a simple +element in the index alist when it matches; the latter creates a +special element of the form (INDEX-NAME POSITION-MARKER FUNCTION +ARGUMENTS...) with FUNCTION and ARGUMENTS copied from PATTERNS. + +MENU-TITLE is a string used as the title for the submenu or nil +if the entries are not nested. + +REGEXP is a regexp that should match a construct in the buffer +that is to be displayed in the menu; i.e., function or variable +definitions, etc. It contains a substring which is the name to +appear in the menu. See the info section on Regexps for more +information. REGEXP may also be a function, called without +arguments. It is expected to search backwards. It shall return +true and set `match-data' if it finds another element. + +INDEX points to the substring in REGEXP that contains the +name (of the function, variable or type) that is to appear in the +menu. + +The variable `imenu-case-fold-search' determines whether or not the +regexp matches are case sensitive, and `imenu-syntax-alist' can be +used to alter the syntax table for the search. + +See `lisp-imenu-generic-expression' for an example of PATTERNS. + +Returns an index of the current buffer as an alist. The elements in +the alist look like: + (INDEX-NAME . INDEX-POSITION) +or like: + (INDEX-NAME INDEX-POSITION FUNCTION ARGUMENTS...) +They may also be nested index alists like: + (INDEX-NAME . INDEX-ALIST) +depending on PATTERNS." + (let ((index-alist (list 'dummy)) + (case-fold-search (if (or (local-variable-p 'imenu-case-fold-search) + (not (local-variable-p 'font-lock-defaults))) + imenu-case-fold-search + (nth 2 font-lock-defaults))) + (old-table (syntax-table)) + (table (copy-syntax-table (syntax-table))) + (slist imenu-syntax-alist) + prev-pos) + (dolist (syn slist) ; Modify the syntax table used while matching regexps. + (if (numberp (car syn)) ; The char(s) to modify may be a single char or a string. + (modify-syntax-entry (car syn) (cdr syn) table) + (mapc (lambda (c) (modify-syntax-entry c (cdr syn) table)) (car syn)))) + (goto-char (point-max)) + (imenu-progress-message prev-pos 0 t) + (unwind-protect ; for syntax table + (save-match-data + (set-syntax-table table) + (dolist (pat patterns) ; Map over the elements of `imenu-generic-expression'. + (let ((menu-title (car pat)) + (regexp (nth 1 pat)) + (index (nth 2 pat)) + (function (nth 3 pat)) + (rest (nthcdr 4 pat)) + start beg) + (goto-char (point-max)) ; Go backwards for convenience of adding items in order. + (while (and (if (functionp regexp) + (funcall regexp) + (and (re-search-backward regexp nil t) + ;; Do not count invisible definitions. + (let ((invis (imenup-invisible-p (point)))) + (or (not invis) + (progn + (while (and invis (not (bobp))) + (setq invis (not (re-search-backward regexp nil 'MOVE)))) + (not invis)))))) + ;; Exit loop if empty match -it means a bad regexp was specified. + (not (= (match-beginning 0) (match-end 0)))) + (setq start (point)) + ;; Record the start of the line in which the match starts. + ;; That's the official position of this definition. + (goto-char (match-beginning index)) + (beginning-of-line) + (setq beg (point)) + (imenu-progress-message prev-pos nil t) + ;; Add this sort of submenu only when find an item for it, to avoid empty menus. + (unless (assoc menu-title index-alist) (push (list menu-title) index-alist)) + (when imenu-use-markers (setq beg (copy-marker beg))) + (let ((item (if function + (nconc (list (match-string-no-properties index) beg function) + rest) + (cons (match-string-no-properties index) beg))) + ;; This is the desired submenu, starting with its title (or nil). + (menu (assoc menu-title index-alist))) + ;; Insert the item unless it is already present. + (unless (member item (cdr menu)) (setcdr menu (cons item (cdr menu))))) + ;; Go to the start of the match, to make sure we keep making progress backwards. + (goto-char start)))) + (set-syntax-table old-table))) + (imenu-progress-message prev-pos 100 t) + ;; Sort each submenu by position. + ;; This is in case one submenu gets items from two different regexps. + (dolist (item index-alist) + (when (listp item) (setcdr item (sort (cdr item) 'imenu--sort-by-position)))) + (let ((main-element (assq nil index-alist))) + (nconc (delq main-element (delq 'dummy index-alist)) (cdr main-element))))) + + +;; REPLACE ORIGINAL in `imenu.el'. +;; +;; Sort each submenu before splitting submenus, instead of sorting among submenus after. +;; +(defun imenu--mouse-menu (index-alist event &optional title) + "Let the user select from a buffer index from a mouse menu. +INDEX-ALIST is the buffer index. +EVENT is a mouse event. +TITLE is the menu title. +Returns t for rescan, or else an element or subelement of INDEX-ALIST." + (setq index-alist (imenu--split-submenus + (if imenu-sort-function + (mapcar (lambda (sm) + (imenu--sort-submenu sm imenu-sort-function)) + index-alist) + index-alist))) + (if (>= emacs-major-version 22) + (let* ((menu (imenu--split-menu index-alist (or title (buffer-name)))) + (map (imenu--create-keymap (car menu) + (cdr (if (< 1 (length (cdr menu))) + menu + (car (cdr menu))))))) + (popup-menu map event)) + (let* ((menu (imenu--split-menu index-alist (or title (buffer-name)))) + position) + (setq menu (imenu--create-keymap-1 (car menu) + (if (< 1 (length (cdr menu))) + (cdr menu) + (cdr (cadr menu)))) + position (x-popup-menu event menu)) + (cond ((eq position nil) + position) + ;; If one call to x-popup-menu handled the nested menus, + ;; find the result by looking down the menus here. + ((and (listp position) + (numberp (car position)) + (stringp (nth (1- (length position)) position))) + (let ((final menu)) + (while position + (setq final (assq (car position) final) + position (cdr position))) + (or (string= (car final) (car imenu--rescan-item)) + (nthcdr 3 final)))) + ;; If x-popup-menu went just one level and found a leaf item, + ;; return the INDEX-ALIST element for that. + ((and (consp position) + (stringp (car position)) + (null (cdr position))) + (or (string= (car position) (car imenu--rescan-item)) + (assq (car position) index-alist))) + ;; If x-popup-menu went just one level + ;; and found a non-leaf item (a submenu), + ;; recurse to handle the rest. + ((listp position) + (imenu--mouse-menu position event + (if title + (concat title imenu-level-separator + (car (rassq position index-alist))) + (car (rassq position index-alist))))))))) + +;;;;;;;;;;;;;;;;;; + +(provide 'imenu+) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; imenu+.el ends here diff --git a/lisp/ispell-multi.el b/lisp/ispell-multi.el new file mode 100644 index 0000000..2dab982 --- /dev/null +++ b/lisp/ispell-multi.el @@ -0,0 +1,445 @@ +;; ispell-multi.el -- multiple ispell processes and multiple flyspell languages +;; +;; Copyright (C) 2005 P J Heslin +;; +;; Author: Peter Heslin +;; URL: http://www.dur.ac.uk/p.j.heslin/Software/Emacs +;; Version: 1.2 +;; +;; 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, 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. +;; +;; If you do not have a copy of the GNU General Public License, you +;; can obtain one by writing to the Free Software Foundation, Inc., 59 +;; Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +;;; Overview: +;; +;; ispell-multi.el enables Emacs to keep a number of ispell processes +;; alive in order to spell-check text efficiently in multiple +;; languages, and it provides a hook that tells flyspell to switch +;; languages depending on the value of a particular text property. +;; +;; Normally, ispell.el only ever keeps one ispell/aspell process +;; alive. So if you have one buffer in which an English local +;; dictionary is used and another in which a German dictionary is +;; used, the ispell process will be killed and restarted every time +;; you run ispell in the other buffer. This is not really a problem, +;; since doing a spellcheck is infrequent and slow anyway. If you are +;; using flyspell-mode, however, the ispell process will be restarted +;; every time you switch buffers. Even this may not matter too much +;; to many people, since switching buffers is also a somewhat slow +;; operation. +;; +;; Where the need for multiple ispell processes becomes really acute +;; is in buffers that have multiple languages in them and a way of +;; telling flyspell to switch local dictionaries depending on where +;; point is. In this case, the starting and stopping of ispell +;; processes very visibly impedes the fluid movement of the cursor. +;; +;; I have written two packages that provide this sort of behavior. +;; One is flyspell-xml-lang.el, which tells flyspell what the local +;; language is in xml files depending on xml:lang attributes, and +;; another is flyspell-babel.el, which does the same with Babel +;; commands in LaTeX files. +;; +;; The present package modifies ispell.el (via defadvice) so that +;; multiple ispell processes are kept alive to check different +;; languages. It requires version 3.6 of ispell, so users of Emacs +;; 21.3 and earlier will have to upgrade. This has only been tested +;; with GNU Emacs. +;; +;; To install this package, just put it somewhere in your load-path +;; and put a (require 'ispell-multi) statement in your .emacs file. + +;;; Using ispell-multi +;; +;; If all you want to do is to change the behavior of ispell so that +;; it uses multiple ispell processes for different buffers, then +;; (require 'ispell-multi) is all you need to do. The rest of this +;; section is for those who want to modify flyspell to switch +;; languages within a buffer. See flyspell-xml-lang.el and +;; flyspell-babel.el for examples of the usage of all of the +;; facilities described below. +;; +;; Flyspell-mode provides a hook that runs before checking each word; +;; this allows you to change the value of ispell-local-dictionary to a +;; different language, depending on the context. If you have a +;; package that parses a buffer and figures out what languages are in +;; it and where they are, you can tell flyspell about it by setting +;; the text property `ispell-multi-lang' to the correct ispell +;; language (this can be any value that ispell-change-dictionary +;; accepts). Your package should set the value of the buffer-local +;; variable `flyspell-generic-check-word-predicate' to the symbol +;; `ispell-multi-verify'; do this *after* you have turned on +;; flyspell-mode. + +;; If you the set the buffer-local variable +;; `ispell-multi-nil-callback' to a symbol, the associated +;; function will be called every time flyspell is called to check a +;; word, and the `ispell-multi-lang' text property returns nil. This +;; function can be used to parse the buffer incrementally and set the +;; text-property lazily as the user moves through the buffer. +;; +;; Since the parser callback is only invoked when the text-property is +;; nil, there is a possibility that the already-set text-property and +;; the changed contents of the buffer will get out of sync. To fix +;; this you will probably also want to arrange for the parser to be +;; run by an idle-timer. You can arrange for this by calling the +;; function `ispell-multi-idler-setup' with a single argument, giving +;; the delay. This will run the function specified by +;; `ispell-multi-idler-callback' after the specified idle time. +;; +;; If you want to indicate that some text should not be spell-checked, +;; set the `ispell-multi-lang' text property to the string "void". To +;; indicate a reversion to the default ispell dictionary, use the +;; string "default". + +;;; Aspell vs. Ispell +;; +;; ispell.el and ispell-multi.el will work happily with aspell instead +;; of ispell, since the former can emulate the latter. Aspell has +;; many advantages over ispell, including a very large selection of +;; language dictionaries, and it is much better able to suggest the +;; correct spelling (which is quite handy when using +;; flyspell-auto-correct-previous-word). If you prefer to use aspell, +;; you can put the following into your .emacs: +;; +;; (setq ispell-program-name "aspell") +;; (setq ispell-really-aspell t) +;; (setq ispell-extra-args '("--sug-mode=fast")) +;; +;; The first two lines tell ispell.el to run aspell instead of ispell, +;; and the third line tells aspell not to use its default algorithm +;; for suggesting spellings, but to use a faster one; the default is +;; very accurate, but can be a bit slow for use with flyspell. If +;; this is not fast enough, try "ultra" instead of "fast" (but even +;; ultra mode is still two times slower than ispell). +;; +;; If you are installing a new aspell dictionary that ispell.el does +;; not know about, you will have to add it to +;; ispell-local-dictionary-alist; see the documentation of +;; flyspell-xml-lang.el for an example. + +;;; Bugs and Limitations +;; +;; If you change ispell dictionaries by using the function +;; `ispell-change-dictionary', then an ispell process will be killed, +;; where it would not have been if you had simply set +;; ispell-local-dictionary. That's because this package just modifies +;; the way ispell deals with local variables like +;; ispell-local-dictionary; it doesn't touch the +;; ispell-change-dictionary function. Maybe it should. The necessary +;; ispell process will be re-started next time you need it, so this is +;; not really a bug so much as a slight performance issue. +;; +;; We try to share ispell processes between buffers, so that a single +;; process can service all buffers or regions in a given language. +;; But if you put buffer-local variables that modify the behavior of +;; ispell for a given buffer (such as LocalWords), then that buffer's +;; ispell processes will not be shared. +;; +;; flyspell-large-region, which is the fast mode of flyspell that it +;; uses when checking the entirety of a large buffer, does not work at +;; all, since it depends on launching a single ispell process for this +;; purpose and so cannot cope with multiple languages. For this +;; reason, flyspell-large-region should be disabled in buffers using +;; this package. +;; +;; It might have been nice to put in here the code to inspect a +;; text-property to find out the language of the text, so that ispell +;; (as opposed to flyspell) would obey the property and change +;; dictionary accordingly. This won't work, though, since +;; ispell-region works on a line-by-line basis, which would fail in +;; the case of a mid-line language-switch. + +;;; Changes +;; +;; 1.0 Pre-release +;; 1.1 Worked around ispell-current-dictionary / ispell-dictionary +;; inconsistency in Emacs CVS / stand-alone ispell.el +;; 1.2 Protect better against errors when switching to an undefined or +;; uninstalled dictionary -- errors in post-command-hook will +;; switch off flyspell, cua, etc. +;; 1.3 Changed process management so that an ispell process without +;; buffer-local modifications will only be killed when all buffers +;; that have used that process have been killed. + +(require 'ispell) +;; For Emacs 21.3, we have to use an updated ispell.el (3.6 or from +;; Emacs CVS), and for some reason we may have to load it again to get +;; ispell-dictionary-alist set properly. +(unless (assoc "english" ispell-dictionary-alist) + (load "ispell")) +;; For updated ispell.el with emacs < 21.3.5 +(when (not (fboundp 'set-process-query-on-exit-flag)) + (defun set-process-query-on-exit-flag (one two) ())) + +; In current Emacs CVS, the variable ispell-current-dictionary is used +; to indicate the dictionary associated with the current ispell +; process, while in the current, separately distributed version of +; ispell.el (3.7beta), this variable does not exist, and +; ispell-dictionary serves this purpose. +(defvar ispell-multi-current-dictionary-var + (if (boundp 'ispell-current-dictionary) + 'ispell-current-dictionary + 'ispell-dictionary)) + +(defvar ispell-multi-dict nil + "The language that this package thinks is current in this + buffer. We don't set ispell-local-dictionary directly, since + we want that to contain the default fall-back in case + ispell-multi-dict is not set.") +(make-variable-buffer-local 'ispell-multi-dict) + + +(defvar ispell-multi-lang-process nil + "Alist mapping languages to ispell processes. Only for + processes without any buffer-local modifications") + +(defvar ispell-multi-lang-process-local nil + "As ispell-multi-lang-process, but a buffer-local alist, to use + for processes with buffer-local modifications") +(make-variable-buffer-local 'ispell-multi-lang-process-local) + +(defvar ispell-multi-flyspell-verify-default nil + "The original value of `flyspell-generic-check-word-predicate', + before it was overridden in order to invoke this package; taken + from the the `flyspell-mode-predicate' property of the major + mode name.") +(make-variable-buffer-local 'ispell-multi-flyspell-verify-default) + +(defvar ispell-multi-nil-callback nil + "Buffer local variable that indicates a function to call when + flyspell is checking a word and the text property + `ispell-multi-lang' is nil. This function will normally set + that property at point and for some of the text in the + neighborhood") +(make-variable-buffer-local 'ispell-multi-nil-callback) + +(defvar ispell-multi-idler-callback nil + "Buffer local variable that indicates a function to call when + idle. Can be used to parse part or all of the buffer.") +(make-variable-buffer-local 'ispell-multi-idler-callback) + +(defvar ispell-multi-verbose nil + "If non-nil, print diagnostic messages about switching dictionaries") + +(defvar ispell-multi-valid-dictionary-list nil + "Cached value of ispell-valid-dictionary-list.") +(when (fboundp 'ispell-valid-dictionary-list) + (setq ispell-multi-valid-dictionary-list + (ispell-valid-dictionary-list))) + +(defvar ispell-multi-bad-language nil + "A list of languages that ispell has choked on. After the + first attempt, we stop trying to start ispell processes for + this language, since flyspell will try to do so incessantly and + cursor motion will get sluggish") + +;; Reset on re-load +(setq ispell-multi-bad-language nil) + +;; This is our hook into ispell.el. +(defadvice ispell-accept-buffer-local-defs (around ispell-multi-advice activate) + "Advice that changes ispell to enable multiple ispell processes." + ;; Bind ispell-local-dictionary + (let* ((ispell-local-dictionary + (if (or (equal ispell-multi-dict "void") + (equal ispell-multi-dict "default") + (null ispell-multi-dict)) + ispell-local-dictionary + ispell-multi-dict)) + (local-mods (ispell-multi-buffer-local-modifications-p)) + (alist (if local-mods + 'ispell-multi-lang-process-local + 'ispell-multi-lang-process)) + (stored-process (cdr (assoc ispell-local-dictionary (symbol-value alist))))) + + ;; Store the currently running process if we haven't already + (when (and ispell-process + (eq (process-status ispell-process) 'run)) + (when (not (rassq ispell-process (symbol-value alist))) + (set alist (cons (cons (symbol-value ispell-multi-current-dictionary-var) ispell-process) + (symbol-value alist)))) + ;; Make a note that this buffer has used this process + (when (not (memq (current-buffer) + (process-get ispell-process 'ispell-multi-buffers))) + (process-put ispell-process 'ispell-multi-buffers + (cons (current-buffer) + (process-get ispell-process 'ispell-multi-buffers))))) + + ;; Do we already have a process for this language? + (if (and stored-process + (eq (process-status stored-process) 'run)) + (progn + (setq ispell-process stored-process) + ;; When ispell-current-dictionary / ispell-dictionary is + ;; the same as ispell-local-dictionary, ispell.el will + ;; refrain from killing the process + (set ispell-multi-current-dictionary-var ispell-local-dictionary)) + + ;; This is to fool ispell into not killing the old process when + ;; it starts the new one. But we don't want a new process if + ;; the current one is correct, or if the default dict is void. + (unless (or (equal (symbol-value ispell-multi-current-dictionary-var) ispell-local-dictionary) + (equal ispell-local-dictionary "void")) + (setq ispell-process nil)) + + ;; Possibly start a new process + (unless (equal ispell-local-dictionary "void") ; ensure against error + ad-do-it)))) + + +(defun ispell-multi-kill-processes-hook () + "Kill orphaned ispell processes." + (dolist (proc (process-list)) + (let* ((old-list (process-get proc 'ispell-multi-buffers)) + (new-list (delete (current-buffer) old-list))) + (when (and old-list (not new-list) + (eq (process-status proc) 'run)) + (setq ispell-process proc) + (ispell-kill-ispell)))) + (ispell-multi-processes-alist-cleanup)) + +(add-hook 'kill-buffer-hook 'ispell-multi-kill-processes-hook) + +(defun ispell-multi-processes-alist-cleanup () + "Remove any defunct processes from the global alist" + (let ((newlist)) + (while ispell-multi-lang-process + (when (eq (process-status (cdar ispell-multi-lang-process)) 'run) + (setq newlist (cons (car ispell-multi-lang-process) newlist))) + (setq ispell-multi-lang-process (cdr ispell-multi-lang-process))) + (setq ispell-multi-lang-process (nreverse newlist)))) + +(defvar ispell-multi-local-regexp + (mapconcat 'regexp-quote (list ispell-dictionary-keyword + ispell-pdict-keyword + ispell-words-keyword) "\\|")) + +(defun ispell-multi-buffer-local-modifications-p () + (save-excursion + (goto-char (point-max)) + (re-search-backward ispell-multi-local-regexp nil t))) + +(defun ispell-multi-verify () + ;; Possibly initialize value of default function + (unless ispell-multi-flyspell-verify-default + (setq ispell-multi-flyspell-verify-default + (or (get major-mode 'flyspell-mode-predicate) + 'none))) + (let ((do-check t) + ;; NB. Adding text properties via the callback will call + ;; after-change-functions, to which flyspell adds a function + ;; that can trigger an infinite loop: flyspell-word changes + ;; the buffer, which can add a value to flyspell-changes, so + ;; that list never goes to nil + (after-change-functions nil)) + ;; Don't switch language if we're not supposed to check this bit anyway + (when (not (eq ispell-multi-flyspell-verify-default 'none)) + (setq do-check (funcall ispell-multi-flyspell-verify-default))) + (when do-check + (let* ((current-position (point)) + (lang (get-text-property current-position 'ispell-multi-lang))) + (when (and (not lang) + ispell-multi-nil-callback) + (ispell-multi-message "parsing ...") + (save-excursion + (funcall ispell-multi-nil-callback)) + (ispell-multi-message "finished parsing.") + (setq lang (get-text-property current-position 'ispell-multi-lang))) + (when lang + (unless (string= ispell-multi-dict lang) + (let ((old-lang ispell-multi-dict)) + (cond + ((string= lang "void") + (setq do-check nil) +; (ispell-multi-message "current dictionary is void: not checking") + ) + ((and ispell-multi-valid-dictionary-list + (member lang ispell-multi-valid-dictionary-list) + (not (member lang ispell-multi-bad-language))) + (ispell-multi-message (concat "dictionary changing to: " lang)) + (setq ispell-multi-dict lang) + ;; Be paranoid, since this can be called from a post-command hook + (condition-case nil + (ispell-accept-buffer-local-defs) + (error (progn + (ispell-multi-message + (concat "Error: ispell didn't like language " lang) t) + (setq ispell-multi-bad-language (cons lang ispell-multi-bad-language)) + (setq do-check nil) + (setq ispell-multi-dict old-lang))))) + (t + (ispell-multi-message + (concat "Warning: no dictionary defined for " lang)) + (setq do-check nil)))))))) + do-check)) + +(defvar ispell-multi-ticker 0) +(defvar ispell-multi-old-point 0) +(make-variable-buffer-local 'ispell-multi-ticker) +(make-variable-buffer-local 'ispell-multi-old-point) + +(defun ispell-multi-idler () + (when (and flyspell-mode + (eq flyspell-generic-check-word-predicate 'ispell-multi-verify) + (not (= (buffer-modified-tick) ispell-multi-ticker)) + (not (= (point) ispell-multi-old-point))) + (let ((old-lang (get-text-property (point) 'ispell-multi-lang)) + new-lang) + (when ispell-multi-idler-callback + (ispell-multi-message "parsing (idle) ...") + (let ((after-change-functions nil)) + (save-excursion + (funcall ispell-multi-idler-callback))) + (ispell-multi-message "finished parsing.") + (setq new-lang (get-text-property (point) 'ispell-multi-lang)) + (unless (or (equal old-lang new-lang) + (equal new-lang "void")) + (setq ispell-multi-dict new-lang) + (ispell-accept-buffer-local-defs))) + (setq ispell-multi-ticker (buffer-modified-tick)) + (setq ispell-multi-old-point (point))))) + +(defvar ispell-multi-idle-timer nil) +(defun ispell-multi-idler-setup (delay) + (unless ispell-multi-idle-timer + (setq ispell-multi-idle-timer + (run-with-idle-timer 5 t 'ispell-multi-idler)))) + +(defun ispell-multi-idler-cancel () + (cancel-timer ispell-multi-idle-timer) + (setq ispell-multi-idle-timer nil)) + +(defun ispell-multi-unhack-flyspell-modeline () + "Remove the flyspell modeline entry" + (setq minor-mode-alist + (delq (assq 'flyspell-mode minor-mode-alist) minor-mode-alist))) + +(defun ispell-multi-hack-flyspell-modeline () + "Add a modeline entry for flyspell that indicates the current + language in parentheses." + (ispell-multi-unhack-flyspell-modeline) + (setq minor-mode-alist + (cons '(flyspell-mode + (:eval + (let ((lang (get-text-property (point) 'ispell-multi-lang))) + (concat flyspell-mode-line-string + (when lang + (concat " (" (capitalize lang) ")")))))) minor-mode-alist))) + +(defun ispell-multi-message (mess &optional force) + (when (or ispell-multi-verbose force) + (message "ispell-multi -- %s" mess))) + +(provide 'ispell-multi) + diff --git a/lisp/no-epy.el b/lisp/no-epy.el new file mode 100644 index 0000000..ee84ec7 --- /dev/null +++ b/lisp/no-epy.el @@ -0,0 +1,2 @@ +(add-to-list 'load-path (expand-file-name "~/.emacs.d")) +(load 'init.el') diff --git a/lisp/package.el b/lisp/package.el new file mode 100644 index 0000000..bb1db1e --- /dev/null +++ b/lisp/package.el @@ -0,0 +1,2161 @@ +;;; package.el --- Simple package system for Emacs -*- lexical-binding:t -*- + +;; Copyright (C) 2007-2014 Free Software Foundation, Inc. + +;; Author: Tom Tromey +;; Daniel Hackney +;; Created: 10 Mar 2007 +;; Version: 1.0.1 +;; Keywords: tools +;; Package-Requires: ((tabulated-list "1.0")) + +;; 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 . + +;;; Change Log: + +;; 2 Apr 2007 - now using ChangeLog file +;; 15 Mar 2007 - updated documentation +;; 14 Mar 2007 - Changed how obsolete packages are handled +;; 13 Mar 2007 - Wrote package-install-from-buffer +;; 12 Mar 2007 - Wrote package-menu mode + +;;; Commentary: + +;; The idea behind package.el is to be able to download packages and +;; install them. Packages are versioned and have versioned +;; dependencies. Furthermore, this supports built-in packages which +;; may or may not be newer than user-specified packages. This makes +;; it possible to upgrade Emacs and automatically disable packages +;; which have moved from external to core. (Note though that we don't +;; currently register any of these, so this feature does not actually +;; work.) + +;; A package is described by its name and version. The distribution +;; format is either a tar file or a single .el file. + +;; A tar file should be named "NAME-VERSION.tar". The tar file must +;; unpack into a directory named after the package and version: +;; "NAME-VERSION". It must contain a file named "PACKAGE-pkg.el" +;; which consists of a call to define-package. It may also contain a +;; "dir" file and the info files it references. + +;; A .el file is named "NAME-VERSION.el" in the remote archive, but is +;; installed as simply "NAME.el" in a directory named "NAME-VERSION". + +;; The downloader downloads all dependent packages. By default, +;; packages come from the official GNU sources, but others may be +;; added by customizing the `package-archives' alist. Packages get +;; byte-compiled at install time. + +;; At activation time we will set up the load-path and the info path, +;; and we will load the package's autoloads. If a package's +;; dependencies are not available, we will not activate that package. + +;; Conceptually a package has multiple state transitions: +;; +;; * Download. Fetching the package from ELPA. +;; * Install. Untar the package, or write the .el file, into +;; ~/.emacs.d/elpa/ directory. +;; * Byte compile. Currently this phase is done during install, +;; but we may change this. +;; * Activate. Evaluate the autoloads for the package to make it +;; available to the user. +;; * Load. Actually load the package and run some code from it. + +;; Other external functions you may want to use: +;; +;; M-x list-packages +;; Enters a mode similar to buffer-menu which lets you manage +;; packages. You can choose packages for install (mark with "i", +;; then "x" to execute) or deletion (not implemented yet), and you +;; can see what packages are available. This will automatically +;; fetch the latest list of packages from ELPA. +;; +;; M-x package-install-from-buffer +;; Install a package consisting of a single .el file that appears +;; in the current buffer. This only works for packages which +;; define a Version header properly; package.el also supports the +;; extension headers Package-Version (in case Version is an RCS id +;; or similar), and Package-Requires (if the package requires other +;; packages). +;; +;; M-x package-install-file +;; Install a package from the indicated file. The package can be +;; either a tar file or a .el file. A tar file must contain an +;; appropriately-named "-pkg.el" file; a .el file must be properly +;; formatted as with package-install-from-buffer. + +;;; Thanks: +;;; (sorted by sort-lines): + +;; Jim Blandy +;; Karl Fogel +;; Kevin Ryde +;; Lawrence Mitchell +;; Michael Olson +;; Sebastian Tennant +;; Stefan Monnier +;; Vinicius Jose Latorre +;; Phil Hagelberg + +;;; ToDo: + +;; - putting info dirs at the start of the info path means +;; users see a weird ordering of categories. OTOH we want to +;; override later entries. maybe emacs needs to enforce +;; the standard layout? +;; - put bytecode in a separate directory tree +;; - perhaps give users a way to recompile their bytecode +;; or do it automatically when emacs changes +;; - give users a way to know whether a package is installed ok +;; - give users a way to view a package's documentation when it +;; only appears in the .el +;; - use/extend checkdoc so people can tell if their package will work +;; - "installed" instead of a blank in the status column +;; - tramp needs its files to be compiled in a certain order. +;; how to handle this? fix tramp? +;; - on emacs 21 we don't kill the -autoloads.el buffer. what about 22? +;; - maybe we need separate .elc directories for various emacs versions +;; and also emacs-vs-xemacs. That way conditional compilation can +;; work. But would this break anything? +;; - should store the package's keywords in archive-contents, then +;; let the users filter the package-menu by keyword. See +;; finder-by-keyword. (We could also let people view the +;; Commentary, but it isn't clear how useful this is.) +;; - William Xu suggests being able to open a package file without +;; installing it +;; - Interface with desktop.el so that restarting after an install +;; works properly +;; - Use hierarchical layout. PKG/etc PKG/lisp PKG/info +;; ... except maybe lisp? +;; - It may be nice to have a macro that expands to the package's +;; private data dir, aka ".../etc". Or, maybe data-directory +;; needs to be a list (though this would be less nice) +;; a few packages want this, eg sokoban +;; - package menu needs: +;; ability to know which packages are built-in & thus not deletable +;; it can sometimes print odd results, like 0.3 available but 0.4 active +;; why is that? +;; - Allow multiple versions on the server...? +;; [ why bother? ] +;; - Don't install a package which will invalidate dependencies overall +;; - Allow something like (or (>= emacs 21.0) (>= xemacs 21.5)) +;; [ currently thinking, why bother.. KISS ] +;; - Allow optional package dependencies +;; then if we require 'bbdb', bbdb-specific lisp in lisp/bbdb +;; and just don't compile to add to load path ...? +;; - Our treatment of the info path is somewhat bogus + +;;; Code: + +(eval-when-compile (require 'cl-lib)) + +(require 'tabulated-list) + +(defgroup package nil + "Manager for Emacs Lisp packages." + :group 'applications + :version "24.1") + +;;;###autoload +(defcustom package-enable-at-startup t + "Whether to activate installed packages when Emacs starts. +If non-nil, packages are activated after reading the init file +and before `after-init-hook'. Activation is not done if +`user-init-file' is nil (e.g. Emacs was started with \"-q\"). + +Even if the value is nil, you can type \\[package-initialize] to +activate the package system at any time." + :type 'boolean + :group 'package + :version "24.1") + +(defcustom package-load-list '(all) + "List of packages for `package-initialize' to load. +Each element in this list should be a list (NAME VERSION), or the +symbol `all'. The symbol `all' says to load the latest installed +versions of all packages not specified by other elements. + +For an element (NAME VERSION), NAME is a package name (a symbol). +VERSION should be t, a string, or nil. +If VERSION is t, the most recent version is activated. +If VERSION is a string, only that version is ever loaded. + Any other version, even if newer, is silently ignored. + Hence, the package is \"held\" at that version. +If VERSION is nil, the package is not loaded (it is \"disabled\")." + :type '(repeat symbol) + :risky t + :group 'package + :version "24.1") + +(defvar Info-directory-list) +(declare-function info-initialize "info" ()) +(declare-function url-http-file-exists-p "url-http" (url)) +(declare-function lm-header "lisp-mnt" (header)) +(declare-function lm-commentary "lisp-mnt" (&optional file)) + +(defcustom package-archives '(("gnu" . "http://elpa.gnu.org/packages/")) + "An alist of archives from which to fetch. +The default value points to the GNU Emacs package repository. + +Each element has the form (ID . LOCATION). + ID is an archive name, as a string. + LOCATION specifies the base location for the archive. + If it starts with \"http:\", it is treated as a HTTP URL; + otherwise it should be an absolute directory name. + (Other types of URL are currently not supported.) + +Only add locations that you trust, since fetching and installing +a package can run arbitrary code." + :type '(alist :key-type (string :tag "Archive name") + :value-type (string :tag "URL or directory name")) + :risky t + :group 'package + :version "24.1") + +(defcustom package-pinned-packages nil + "An alist of packages that are pinned to specific archives. +This can be useful if you have multiple package archives enabled, +and want to control which archive a given package gets installed from. + +Each element of the alist has the form (PACKAGE . ARCHIVE), where: + PACKAGE is a symbol representing a package + ARCHIVE is a string representing an archive (it should be the car of +an element in `package-archives', e.g. \"gnu\"). + +Adding an entry to this variable means that only ARCHIVE will be +considered as a source for PACKAGE. If other archives provide PACKAGE, +they are ignored (for this package). If ARCHIVE does not contain PACKAGE, +the package will be unavailable." + :type '(alist :key-type (symbol :tag "Package") + :value-type (string :tag "Archive name")) + ;; I don't really see why this is risky... + ;; I suppose it could prevent you receiving updates for a package, + ;; via an entry (PACKAGE . NON-EXISTING). Which could be an issue + ;; if PACKAGE has a known vulnerability that is fixed in newer versions. + :risky t + :group 'package + :version "24.4") + +(defconst package-archive-version 1 + "Version number of the package archive understood by this file. +Lower version numbers than this will probably be understood as well.") + +;; We don't prime the cache since it tends to get out of date. +(defvar package-archive-contents nil + "Cache of the contents of the Emacs Lisp Package Archive. +This is an alist mapping package names (symbols) to +non-empty lists of `package-desc' structures.") +(put 'package-archive-contents 'risky-local-variable t) + +(defcustom package-user-dir (locate-user-emacs-file "elpa") + "Directory containing the user's Emacs Lisp packages. +The directory name should be absolute. +Apart from this directory, Emacs also looks for system-wide +packages in `package-directory-list'." + :type 'directory + :risky t + :group 'package + :version "24.1") + +(defcustom package-directory-list + ;; Defaults are subdirs named "elpa" in the site-lisp dirs. + (let (result) + (dolist (f load-path) + (and (stringp f) + (equal (file-name-nondirectory f) "site-lisp") + (push (expand-file-name "elpa" f) result))) + (nreverse result)) + "List of additional directories containing Emacs Lisp packages. +Each directory name should be absolute. + +These directories contain packages intended for system-wide; in +contrast, `package-user-dir' contains packages for personal use." + :type '(repeat directory) + :risky t + :group 'package + :version "24.1") + +(defcustom package-check-signature + (if (progn (require 'epg-config) (executable-find epg-gpg-program)) + 'allow-unsigned) + "Non-nil means to check package signatures when installing. +The value `allow-unsigned' means to still install a package even if +it is unsigned. + +This also applies to the \"archive-contents\" file that lists the +contents of the archive." + :type '(choice (const nil :tag "Never") + (const allow-unsigned :tag "Allow unsigned") + (const t :tag "Check always")) + :risky t + :group 'package + :version "24.4") + +(defcustom package-unsigned-archives nil + "List of archives where we do not check for package signatures." + :type '(repeat (string :tag "Archive name")) + :risky t + :group 'package + :version "24.4") + +(defvar package--default-summary "No description available.") + +(cl-defstruct (package-desc + ;; Rename the default constructor from `make-package-desc'. + (:constructor package-desc-create) + ;; Has the same interface as the old `define-package', + ;; which is still used in the "foo-pkg.el" files. Extra + ;; options can be supported by adding additional keys. + (:constructor + package-desc-from-define + (name-string version-string &optional summary requirements + &rest rest-plist + &aux + (name (intern name-string)) + (version (version-to-list version-string)) + (reqs (mapcar #'(lambda (elt) + (list (car elt) + (version-to-list (cadr elt)))) + (if (eq 'quote (car requirements)) + (nth 1 requirements) + requirements))) + (kind (plist-get rest-plist :kind)) + (archive (plist-get rest-plist :archive)) + (extras (let (alist) + (while rest-plist + (unless (memq (car rest-plist) '(:kind :archive)) + (let ((value (cadr rest-plist))) + (when value + (push (cons (car rest-plist) + (if (eq (car-safe value) 'quote) + (cadr value) + value)) + alist)))) + (setq rest-plist (cddr rest-plist))) + alist))))) + "Structure containing information about an individual package. +Slots: + +`name' Name of the package, as a symbol. + +`version' Version of the package, as a version list. + +`summary' Short description of the package, typically taken from + the first line of the file. + +`reqs' Requirements of the package. A list of (PACKAGE + VERSION-LIST) naming the dependent package and the minimum + required version. + +`kind' The distribution format of the package. Currently, it is + either `single' or `tar'. + +`archive' The name of the archive (as a string) whence this + package came. + +`dir' The directory where the package is installed (if installed), + `builtin' if it is built-in, or nil otherwise. + +`extras' Optional alist of additional keyword-value pairs. + +`signed' Flag to indicate that the package is signed by provider." + name + version + (summary package--default-summary) + reqs + kind + archive + dir + extras + signed) + +;; Pseudo fields. +(defun package-desc-full-name (pkg-desc) + (format "%s-%s" + (package-desc-name pkg-desc) + (package-version-join (package-desc-version pkg-desc)))) + +(defun package-desc-suffix (pkg-desc) + (pcase (package-desc-kind pkg-desc) + (`single ".el") + (`tar ".tar") + (kind (error "Unknown package kind: %s" kind)))) + +(defun package-desc--keywords (pkg-desc) + (let ((keywords (cdr (assoc :keywords (package-desc-extras pkg-desc))))) + (if (eq (car-safe keywords) 'quote) + (nth 1 keywords) + keywords))) + +;; Package descriptor format used in finder-inf.el and package--builtins. +(cl-defstruct (package--bi-desc + (:constructor package-make-builtin (version summary)) + (:type vector)) + version + reqs + summary) + +(defvar package--builtins nil + "Alist of built-in packages. +The actual value is initialized by loading the library +`finder-inf'; this is not done until it is needed, e.g. by the +function `package-built-in-p'. + +Each element has the form (PKG . PACKAGE-BI-DESC), where PKG is a package +name (a symbol) and DESC is a `package--bi-desc' structure.") +(put 'package--builtins 'risky-local-variable t) + +(defvar package-alist nil + "Alist of all packages available for activation. +Each element has the form (PKG . DESCS), where PKG is a package +name (a symbol) and DESCS is a non-empty list of `package-desc' structure, +sorted by decreasing versions. + +This variable is set automatically by `package-load-descriptor', +called via `package-initialize'. To change which packages are +loaded and/or activated, customize `package-load-list'.") +(put 'package-alist 'risky-local-variable t) + +(defvar package-activated-list nil + ;; FIXME: This should implicitly include all builtin packages. + "List of the names of currently activated packages.") +(put 'package-activated-list 'risky-local-variable t) + +(defun package-version-join (vlist) + "Return the version string corresponding to the list VLIST. +This is, approximately, the inverse of `version-to-list'. +\(Actually, it returns only one of the possible inverses, since +`version-to-list' is a many-to-one operation.)" + (if (null vlist) + "" + (let ((str-list (list "." (int-to-string (car vlist))))) + (dolist (num (cdr vlist)) + (cond + ((>= num 0) + (push (int-to-string num) str-list) + (push "." str-list)) + ((< num -4) + (error "Invalid version list `%s'" vlist)) + (t + ;; pre, or beta, or alpha + (cond ((equal "." (car str-list)) + (pop str-list)) + ((not (string-match "[0-9]+" (car str-list))) + (error "Invalid version list `%s'" vlist))) + (push (cond ((= num -1) "pre") + ((= num -2) "beta") + ((= num -3) "alpha") + ((= num -4) "snapshot")) + str-list)))) + (if (equal "." (car str-list)) + (pop str-list)) + (apply 'concat (nreverse str-list))))) + +(defun package-load-descriptor (pkg-dir) + "Load the description file in directory PKG-DIR." + (let ((pkg-file (expand-file-name (package--description-file pkg-dir) + pkg-dir)) + (signed-file (concat pkg-dir ".signed"))) + (when (file-exists-p pkg-file) + (with-temp-buffer + (insert-file-contents pkg-file) + (goto-char (point-min)) + (let ((pkg-desc (package-process-define-package + (read (current-buffer)) pkg-file))) + (setf (package-desc-dir pkg-desc) pkg-dir) + (if (file-exists-p signed-file) + (setf (package-desc-signed pkg-desc) t)) + pkg-desc))))) + +(defun package-load-all-descriptors () + "Load descriptors for installed Emacs Lisp packages. +This looks for package subdirectories in `package-user-dir' and +`package-directory-list'. The variable `package-load-list' +controls which package subdirectories may be loaded. + +In each valid package subdirectory, this function loads the +description file containing a call to `define-package', which +updates `package-alist'." + (dolist (dir (cons package-user-dir package-directory-list)) + (when (file-directory-p dir) + (dolist (subdir (directory-files dir)) + (let ((pkg-dir (expand-file-name subdir dir))) + (when (file-directory-p pkg-dir) + (package-load-descriptor pkg-dir))))))) + +(defun package-disabled-p (pkg-name version) + "Return whether PKG-NAME at VERSION can be activated. +The decision is made according to `package-load-list'. +Return nil if the package can be activated. +Return t if the package is completely disabled. +Return the max version (as a string) if the package is held at a lower version." + (let ((force (assq pkg-name package-load-list))) + (cond ((null force) (not (memq 'all package-load-list))) + ((null (setq force (cadr force))) t) ; disabled + ((eq force t) nil) + ((stringp force) ; held + (unless (version-list-= version (version-to-list force)) + force)) + (t (error "Invalid element in `package-load-list'"))))) + +(defun package-activate-1 (pkg-desc) + (let* ((name (package-desc-name pkg-desc)) + (pkg-dir (package-desc-dir pkg-desc)) + (pkg-dir-dir (file-name-as-directory pkg-dir))) + (unless pkg-dir + (error "Internal error: unable to find directory for `%s'" + (package-desc-full-name pkg-desc))) + ;; Add to load path, add autoloads, and activate the package. + (let ((old-lp load-path)) + (with-demoted-errors + (let ((file-name (expand-file-name (format "%s-autoloads.el" name) pkg-dir))) + ; (message "fn1:" file-name) + (package-autoload-ensure-default-file file-name) + ; (message "fn2:" file-name) + (load file-name nil t))) + (when (and (eq old-lp load-path) + (not (or (member pkg-dir load-path) + (member pkg-dir-dir load-path)))) + ;; Old packages don't add themselves to the `load-path', so we have to + ;; do it ourselves. + (push pkg-dir load-path))) + ;; Add info node. + (when (file-exists-p (expand-file-name "dir" pkg-dir)) + ;; FIXME: not the friendliest, but simple. + (require 'info) + (info-initialize) + (push pkg-dir Info-directory-list)) + (push name package-activated-list) + ;; Don't return nil. + t)) + +(defun package-built-in-p (package &optional min-version) + "Return true if PACKAGE is built-in to Emacs. +Optional arg MIN-VERSION, if non-nil, should be a version list +specifying the minimum acceptable version." + (if (package-desc-p package) ;; was built-in and then was converted + (eq 'builtin (package-desc-dir package)) + (let ((bi (assq package package--builtin-versions))) + (cond + (bi (version-list-<= min-version (cdr bi))) + ((remove 0 min-version) nil) + (t + (require 'finder-inf nil t) ; For `package--builtins'. + (assq package package--builtins)))))) + +(defun package--from-builtin (bi-desc) + (package-desc-create :name (pop bi-desc) + :version (package--bi-desc-version bi-desc) + :summary (package--bi-desc-summary bi-desc) + :dir 'builtin)) + +;; This function goes ahead and activates a newer version of a package +;; if an older one was already activated. This is not ideal; we'd at +;; least need to check to see if the package has actually been loaded, +;; and not merely activated. +(defun package-activate (package &optional force) + "Activate package PACKAGE. +If FORCE is true, (re-)activate it if it's already activated." + (let ((pkg-descs (cdr (assq package package-alist)))) + ;; Check if PACKAGE is available in `package-alist'. + (while + (when pkg-descs + (let ((available-version (package-desc-version (car pkg-descs)))) + (or (package-disabled-p package available-version) + ;; Prefer a builtin package. + (package-built-in-p package available-version)))) + (setq pkg-descs (cdr pkg-descs))) + (cond + ;; If no such package is found, maybe it's built-in. + ((null pkg-descs) + (package-built-in-p package)) + ;; If the package is already activated, just return t. + ((and (memq package package-activated-list) (not force)) + t) + ;; Otherwise, proceed with activation. + (t + (let* ((pkg-vec (car pkg-descs)) + (fail (catch 'dep-failure + ;; Activate its dependencies recursively. + (dolist (req (package-desc-reqs pkg-vec)) + (unless (package-activate (car req) (cadr req)) + (throw 'dep-failure req)))))) + (if fail + (warn "Unable to activate package `%s'. +Required package `%s-%s' is unavailable" + package (car fail) (package-version-join (cadr fail))) + ;; If all goes well, activate the package itself. + (package-activate-1 pkg-vec))))))) + +(defun define-package (_name-string _version-string + &optional _docstring _requirements + &rest _extra-properties) + "Define a new package. +NAME-STRING is the name of the package, as a string. +VERSION-STRING is the version of the package, as a string. +DOCSTRING is a short description of the package, a string. +REQUIREMENTS is a list of dependencies on other packages. + Each requirement is of the form (OTHER-PACKAGE OTHER-VERSION), + where OTHER-VERSION is a string. + +EXTRA-PROPERTIES is currently unused." + ;; FIXME: Placeholder! Should we keep it? + (error "Don't call me!")) + +(defun package-process-define-package (exp origin) + (unless (eq (car-safe exp) 'define-package) + (error "Can't find define-package in %s" origin)) + (let* ((new-pkg-desc (apply #'package-desc-from-define (cdr exp))) + (name (package-desc-name new-pkg-desc)) + (version (package-desc-version new-pkg-desc)) + (old-pkgs (assq name package-alist))) + (if (null old-pkgs) + ;; If there's no old package, just add this to `package-alist'. + (push (list name new-pkg-desc) package-alist) + ;; If there is, insert the new package at the right place in the list. + (while + (if (and (cdr old-pkgs) + (version-list-< version + (package-desc-version (cadr old-pkgs)))) + (setq old-pkgs (cdr old-pkgs)) + (push new-pkg-desc (cdr old-pkgs)) + nil))) + new-pkg-desc)) + +;; From Emacs 22, but changed so it adds to load-path. +(defun package-autoload-ensure-default-file (file) + "Make sure that the autoload file FILE exists and if not create it." + (unless (file-exists-p file) + (write-region + (concat ";;; " (file-name-nondirectory file) + " --- automatically extracted autoloads\n" + ";;\n" + ";;; Code:\n" + "(add-to-list 'load-path (or (file-name-directory #$) (car load-path)))\n" + " \n;; Local Variables:\n" + ";; version-control: never\n" + ";; no-byte-compile: t\n" + ";; no-update-autoloads: t\n" + ";; End:\n" + ";;; " (file-name-nondirectory file) + " ends here\n") + nil file nil 'silent)) + file) + +(defvar generated-autoload-file) +(defvar version-control) + +(defun package-generate-autoloads (name pkg-dir) + (let* ((auto-name (format "%s-autoloads.el" name)) + ;;(ignore-name (concat name "-pkg.el")) + (generated-autoload-file (expand-file-name auto-name pkg-dir)) + (version-control 'never)) + (package-autoload-ensure-default-file generated-autoload-file) + (update-directory-autoloads pkg-dir) + (let ((buf (find-buffer-visiting generated-autoload-file))) + (when buf (kill-buffer buf))) + auto-name)) + +(defvar tar-parse-info) +(declare-function tar-untar-buffer "tar-mode" ()) +(declare-function tar-header-name "tar-mode" (tar-header) t) +(declare-function tar-header-link-type "tar-mode" (tar-header) t) + +(defun package-untar-buffer (dir) + "Untar the current buffer. +This uses `tar-untar-buffer' from Tar mode. All files should +untar into a directory named DIR; otherwise, signal an error." + (require 'tar-mode) + (tar-mode) + ;; Make sure everything extracts into DIR. + (let ((regexp (concat "\\`" (regexp-quote (expand-file-name dir)) "/")) + (case-fold-search (memq system-type '(windows-nt ms-dos cygwin)))) + (dolist (tar-data tar-parse-info) + (let ((name (expand-file-name (tar-header-name tar-data)))) + (or (string-match regexp name) + ;; Tarballs created by some utilities don't list + ;; directories with a trailing slash (Bug#13136). + (and (string-equal dir name) + (eq (tar-header-link-type tar-data) 5)) + (error "Package does not untar cleanly into directory %s/" dir))))) + (tar-untar-buffer)) + +(defun package-generate-description-file (pkg-desc pkg-file) + "Create the foo-pkg.el file for single-file packages." + (let* ((name (package-desc-name pkg-desc))) + (let ((print-level nil) + (print-quoted t) + (print-length nil)) + (write-region + (concat + (prin1-to-string + (nconc + (list 'define-package + (symbol-name name) + (package-version-join (package-desc-version pkg-desc)) + (package-desc-summary pkg-desc) + (let ((requires (package-desc-reqs pkg-desc))) + (list 'quote + ;; Turn version lists into string form. + (mapcar + (lambda (elt) + (list (car elt) + (package-version-join (cadr elt)))) + requires)))) + (package--alist-to-plist-args + (package-desc-extras pkg-desc)))) + "\n") + nil pkg-file nil 'silent)))) + +(defun package--alist-to-plist-args (alist) + (mapcar (lambda (x) + (if (and (not (consp x)) + (or (keywordp x) + (not (symbolp x)) + (memq x '(nil t)))) + x `',x)) + (apply #'nconc + (mapcar (lambda (pair) (list (car pair) (cdr pair))) alist)))) + +(defun package-unpack (pkg-desc) + "Install the contents of the current buffer as a package." + (let* ((name (package-desc-name pkg-desc)) + (dirname (package-desc-full-name pkg-desc)) + (pkg-dir (expand-file-name dirname package-user-dir))) + (pcase (package-desc-kind pkg-desc) + (`tar + (make-directory package-user-dir t) + ;; FIXME: should we delete PKG-DIR if it exists? + (let* ((default-directory (file-name-as-directory package-user-dir))) + (package-untar-buffer dirname))) + (`single + (let ((el-file (expand-file-name (format "%s.el" name) pkg-dir))) + (make-directory pkg-dir t) + (package--write-file-no-coding el-file))) + (kind (error "Unknown package kind: %S" kind))) + (package--make-autoloads-and-stuff pkg-desc pkg-dir) + ;; Update package-alist. + (let ((new-desc (package-load-descriptor pkg-dir))) + ;; FIXME: Check that `new-desc' matches `desc'! + ;; FIXME: Compilation should be done as a separate, optional, step. + ;; E.g. for multi-package installs, we should first install all packages + ;; and then compile them. + (package--compile new-desc)) + ;; Try to activate it. + (package-activate name 'force) + pkg-dir)) + +(defun package--make-autoloads-and-stuff (pkg-desc pkg-dir) + "Generate autoloads, description file, etc.. for PKG-DESC installed at PKG-DIR." + (package-generate-autoloads (package-desc-name pkg-desc) pkg-dir) + (let ((desc-file (expand-file-name (package--description-file pkg-dir) + pkg-dir))) + (unless (file-exists-p desc-file) + (package-generate-description-file pkg-desc desc-file))) + ;; FIXME: Create foo.info and dir file from foo.texi? + ) + +(defun package--compile (pkg-desc) + "Byte-compile installed package PKG-DESC." + (package-activate-1 pkg-desc) + (byte-recompile-directory (package-desc-dir pkg-desc) 0 t)) + +(defun package--write-file-no-coding (file-name) + (let ((buffer-file-coding-system 'no-conversion)) + (write-region (point-min) (point-max) file-name nil 'silent))) + +(defmacro package--with-work-buffer (location file &rest body) + "Run BODY in a buffer containing the contents of FILE at LOCATION. +LOCATION is the base location of a package archive, and should be +one of the URLs (or file names) specified in `package-archives'. +FILE is the name of a file relative to that base location. + +This macro retrieves FILE from LOCATION into a temporary buffer, +and evaluates BODY while that buffer is current. This work +buffer is killed afterwards. Return the last value in BODY." + (declare (indent 2) (debug t)) + `(with-temp-buffer + (if (string-match-p "\\`https?:" ,location) + (url-insert-file-contents (concat ,location ,file)) + (unless (file-name-absolute-p ,location) + (error "Archive location %s is not an absolute file name" + ,location)) + (insert-file-contents (expand-file-name ,file ,location))) + ,@body)) + +(defun package--archive-file-exists-p (location file) + (let ((http (string-match "\\`https?:" location))) + (if http + (progn + (require 'url-http) + (url-http-file-exists-p (concat location file))) + (file-exists-p (expand-file-name file location))))) + +(declare-function epg-make-context "epg" + (&optional protocol armor textmode include-certs + cipher-algorithm + digest-algorithm + compress-algorithm)) +(declare-function epg-context-set-home-directory "epg" (context directory)) +(declare-function epg-verify-string "epg" (context signature + &optional signed-text)) +(declare-function epg-context-result-for "epg" (context name)) +(declare-function epg-signature-status "epg" (signature)) +(declare-function epg-signature-to-string "epg" (signature)) + +(defun package--check-signature (location file) + "Check signature of the current buffer. +GnuPG keyring is located under \"gnupg\" in `package-user-dir'." + (let* ((context (epg-make-context 'OpenPGP)) + (homedir (expand-file-name "gnupg" package-user-dir)) + (sig-file (concat file ".sig")) + (sig-content (package--with-work-buffer location sig-file + (buffer-string)))) + (epg-context-set-home-directory context homedir) + (epg-verify-string context sig-content (buffer-string)) + (let (good-signatures had-fatal-error) + ;; The .sig file may contain multiple signatures. Success if one + ;; of the signatures is good. + (dolist (sig (epg-context-result-for context 'verify)) + (if (eq (epg-signature-status sig) 'good) + (push sig good-signatures) + ;; If package-check-signature is allow-unsigned, don't + ;; signal error when we can't verify signature because of + ;; missing public key. Other errors are still treated as + ;; fatal (bug#17625). + (unless (and (eq package-check-signature 'allow-unsigned) + (eq (epg-signature-status sig) 'no-pubkey)) + (setq had-fatal-error t)))) + (if (and (null good-signatures) had-fatal-error) + (error "Failed to verify signature %s: %S" + sig-file + (mapcar #'epg-signature-to-string + (epg-context-result-for context 'verify))) + good-signatures)))) + +(defun package-install-from-archive (pkg-desc) + "Download and install a tar package." + (let* ((location (package-archive-base pkg-desc)) + (file (concat (package-desc-full-name pkg-desc) + (package-desc-suffix pkg-desc))) + (sig-file (concat file ".sig")) + good-signatures pkg-descs) + (package--with-work-buffer location file + (if (and package-check-signature + (not (member (package-desc-archive pkg-desc) + package-unsigned-archives))) + (if (package--archive-file-exists-p location sig-file) + (setq good-signatures (package--check-signature location file)) + (unless (eq package-check-signature 'allow-unsigned) + (error "Unsigned package: `%s'" + (package-desc-name pkg-desc))))) + (package-unpack pkg-desc)) + ;; Here the package has been installed successfully, mark it as + ;; signed if appropriate. + (when good-signatures + ;; Write out good signatures into NAME-VERSION.signed file. + (write-region (mapconcat #'epg-signature-to-string good-signatures "\n") + nil + (expand-file-name + (concat (package-desc-full-name pkg-desc) + ".signed") + package-user-dir) + nil 'silent) + ;; Update the old pkg-desc which will be shown on the description buffer. + (setf (package-desc-signed pkg-desc) t) + ;; Update the new (activated) pkg-desc as well. + (setq pkg-descs (cdr (assq (package-desc-name pkg-desc) package-alist))) + (if pkg-descs + (setf (package-desc-signed (car pkg-descs)) t))))) + +(defvar package--initialized nil) + +(defun package-installed-p (package &optional min-version) + "Return true if PACKAGE, of MIN-VERSION or newer, is installed. +MIN-VERSION should be a version list." + (unless package--initialized (error "package.el is not yet initialized!")) + (or + (let ((pkg-descs (cdr (assq package package-alist)))) + (and pkg-descs + (version-list-<= min-version + (package-desc-version (car pkg-descs))))) + ;; Also check built-in packages. + (package-built-in-p package min-version))) + +(defun package-compute-transaction (packages requirements &optional seen) + "Return a list of packages to be installed, including PACKAGES. +PACKAGES should be a list of `package-desc'. + +REQUIREMENTS should be a list of additional requirements; each +element in this list should have the form (PACKAGE VERSION-LIST), +where PACKAGE is a package name and VERSION-LIST is the required +version of that package. + +This function recursively computes the requirements of the +packages in REQUIREMENTS, and returns a list of all the packages +that must be installed. Packages that are already installed are +not included in this list. + +SEEN is used internally to detect infinite recursion." + ;; FIXME: We really should use backtracking to explore the whole + ;; search space (e.g. if foo require bar-1.3, and bar-1.4 requires toto-1.1 + ;; whereas bar-1.3 requires toto-1.0 and the user has put a hold on toto-1.0: + ;; the current code might fail to see that it could install foo by using the + ;; older bar-1.3). + (dolist (elt requirements) + (let* ((next-pkg (car elt)) + (next-version (cadr elt)) + (already ())) + (dolist (pkg packages) + (if (eq next-pkg (package-desc-name pkg)) + (setq already pkg))) + (when already + (if (version-list-<= next-version (package-desc-version already)) + ;; `next-pkg' is already in `packages', but its position there + ;; means it might be installed too late: remove it from there, so + ;; we re-add it (along with its dependencies) at an earlier place + ;; below (bug#16994). + (if (memq already seen) ;Avoid inf-loop on dependency cycles. + (message "Dependency cycle going through %S" + (package-desc-full-name already)) + (setq packages (delq already packages)) + (setq already nil)) + (error "Need package `%s-%s', but only %s is being installed" + next-pkg (package-version-join next-version) + (package-version-join (package-desc-version already))))) + (cond + (already nil) + ((package-installed-p next-pkg next-version) nil) + + (t + ;; A package is required, but not installed. It might also be + ;; blocked via `package-load-list'. + (let ((pkg-descs (cdr (assq next-pkg package-archive-contents))) + (found nil) + (problem nil)) + (while (and pkg-descs (not found)) + (let* ((pkg-desc (pop pkg-descs)) + (version (package-desc-version pkg-desc)) + (disabled (package-disabled-p next-pkg version))) + (cond + ((version-list-< version next-version) + (error + "Need package `%s-%s', but only %s is available" + next-pkg (package-version-join next-version) + (package-version-join version))) + (disabled + (unless problem + (setq problem + (if (stringp disabled) + (format "Package `%s' held at version %s, \ +but version %s required" + next-pkg disabled + (package-version-join next-version)) + (format "Required package '%s' is disabled" + next-pkg))))) + (t (setq found pkg-desc))))) + (unless found + (if problem + (error "%s" problem) + (error "Package `%s-%s' is unavailable" + next-pkg (package-version-join next-version)))) + (setq packages + (package-compute-transaction (cons found packages) + (package-desc-reqs found) + (cons found seen)))))))) + packages) + +(defun package-read-from-string (str) + "Read a Lisp expression from STR. +Signal an error if the entire string was not used." + (let* ((read-data (read-from-string str)) + (more-left + (condition-case nil + ;; The call to `ignore' suppresses a compiler warning. + (progn (ignore (read-from-string + (substring str (cdr read-data)))) + t) + (end-of-file nil)))) + (if more-left + (error "Can't read whole string") + (car read-data)))) + +(defun package--read-archive-file (file) + "Re-read archive file FILE, if it exists. +Will return the data from the file, or nil if the file does not exist. +Will throw an error if the archive version is too new." + (let ((filename (expand-file-name file package-user-dir))) + (when (file-exists-p filename) + (with-temp-buffer + (insert-file-contents-literally filename) + (let ((contents (read (current-buffer)))) + (if (> (car contents) package-archive-version) + (error "Package archive version %d is higher than %d" + (car contents) package-archive-version)) + (cdr contents)))))) + +(defun package-read-all-archive-contents () + "Re-read `archive-contents', if it exists. +If successful, set `package-archive-contents'." + (setq package-archive-contents nil) + (dolist (archive package-archives) + (package-read-archive-contents (car archive)))) + +(defun package-read-archive-contents (archive) + "Re-read archive contents for ARCHIVE. +If successful, set the variable `package-archive-contents'. +If the archive version is too new, signal an error." + ;; Version 1 of 'archive-contents' is identical to our internal + ;; representation. + (let* ((contents-file (format "archives/%s/archive-contents" archive)) + (contents (package--read-archive-file contents-file))) + (when contents + (dolist (package contents) + (package--add-to-archive-contents package archive))))) + +;; Package descriptor objects used inside the "archive-contents" file. +;; Changing this defstruct implies changing the format of the +;; "archive-contents" files. +(cl-defstruct (package--ac-desc + (:constructor package-make-ac-desc (version reqs summary kind extras)) + (:copier nil) + (:type vector)) + version reqs summary kind extras) + +(defun package--add-to-archive-contents (package archive) + "Add the PACKAGE from the given ARCHIVE if necessary. +PACKAGE should have the form (NAME . PACKAGE--AC-DESC). +Also, add the originating archive to the `package-desc' structure." + (let* ((name (car package)) + (version (package--ac-desc-version (cdr package))) + (pkg-desc + (package-desc-create + :name name + :version version + :reqs (package--ac-desc-reqs (cdr package)) + :summary (package--ac-desc-summary (cdr package)) + :kind (package--ac-desc-kind (cdr package)) + :archive archive + :extras (and (> (length (cdr package)) 4) + ;; Older archive-contents files have only 4 + ;; elements here. + (package--ac-desc-extras (cdr package))))) + (existing-packages (assq name package-archive-contents)) + (pinned-to-archive (assoc name package-pinned-packages))) + (cond + ;; Skip entirely if pinned to another archive. + ((and pinned-to-archive + (not (equal (cdr pinned-to-archive) archive))) + nil) + ((not existing-packages) + (push (list name pkg-desc) package-archive-contents)) + (t + (while + (if (and (cdr existing-packages) + (version-list-< + version (package-desc-version (cadr existing-packages)))) + (setq existing-packages (cdr existing-packages)) + (push pkg-desc (cdr existing-packages)) + nil)))))) + +(defun package-download-transaction (packages) + "Download and install all the packages in PACKAGES. +PACKAGES should be a list of package-desc. +This function assumes that all package requirements in +PACKAGES are satisfied, i.e. that PACKAGES is computed +using `package-compute-transaction'." + (mapc #'package-install-from-archive packages)) + +;;;###autoload +(defun package-install (pkg) + "Install the package PKG. +PKG can be a package-desc or the package name of one the available packages +in an archive in `package-archives'. Interactively, prompt for its name." + (interactive + (progn + ;; Initialize the package system to get the list of package + ;; symbols for completion. + (unless package--initialized + (package-initialize t)) + (unless package-archive-contents + (package-refresh-contents)) + (list (intern (completing-read + "Install package: " + (delq nil + (mapcar (lambda (elt) + (unless (package-installed-p (car elt)) + (symbol-name (car elt)))) + package-archive-contents)) + nil t))))) + (package-download-transaction + (if (package-desc-p pkg) + (package-compute-transaction (list pkg) + (package-desc-reqs pkg)) + (package-compute-transaction () + (list (list pkg)))))) + +(defun package-strip-rcs-id (str) + "Strip RCS version ID from the version string STR. +If the result looks like a dotted numeric version, return it. +Otherwise return nil." + (when str + (when (string-match "\\`[ \t]*[$]Revision:[ \t]+" str) + (setq str (substring str (match-end 0)))) + (condition-case nil + (if (version-to-list str) + str) + (error nil)))) + +(declare-function lm-homepage "lisp-mnt" (&optional file)) + +(defun package--prepare-dependencies (deps) + "Turn DEPS into an acceptable list of dependencies. + +Any parts missing a version string get a default version string +of \"0\" (meaning any version) and an appropriate level of lists +is wrapped around any parts requiring it." + (cond + ((not (listp deps)) + (error "Invalid requirement specifier: %S" deps)) + (t (mapcar (lambda (dep) + (cond + ((symbolp dep) `(,dep "0")) + ((stringp dep) + (error "Invalid requirement specifier: %S" dep)) + ((and (listp dep) (null (cdr dep))) + (list (car dep) "0")) + (t dep))) + deps)))) + +(defun package-buffer-info () + "Return a `package-desc' describing the package in the current buffer. + +If the buffer does not contain a conforming package, signal an +error. If there is a package, narrow the buffer to the file's +boundaries." + (goto-char (point-min)) + (unless (re-search-forward "^;;; \\([^ ]*\\)\\.el ---[ \t]*\\(.*?\\)[ \t]*\\(-\\*-.*-\\*-[ \t]*\\)?$" nil t) + (error "Package lacks a file header")) + (let ((file-name (match-string-no-properties 1)) + (desc (match-string-no-properties 2)) + (start (line-beginning-position))) + (unless (search-forward (concat ";;; " file-name ".el ends here")) + (error "Package lacks a terminating comment")) + ;; Try to include a trailing newline. + (forward-line) + (narrow-to-region start (point)) + (require 'lisp-mnt) + ;; Use some headers we've invented to drive the process. + (let* ((requires-str (lm-header "package-requires")) + ;; Prefer Package-Version; if defined, the package author + ;; probably wants us to use it. Otherwise try Version. + (pkg-version + (or (package-strip-rcs-id (lm-header "package-version")) + (package-strip-rcs-id (lm-header "version")))) + (homepage (lm-homepage))) + (unless pkg-version + (error + "Package lacks a \"Version\" or \"Package-Version\" header")) + (package-desc-from-define + file-name pkg-version desc + (if requires-str + (package--prepare-dependencies + (package-read-from-string requires-str))) + :kind 'single + :url homepage)))) + +(declare-function tar-get-file-descriptor "tar-mode" (file)) +(declare-function tar--extract "tar-mode" (descriptor)) + +(defun package-tar-file-info () + "Find package information for a tar file. +The return result is a `package-desc'." + (cl-assert (derived-mode-p 'tar-mode)) + (let* ((dir-name (file-name-directory + (tar-header-name (car tar-parse-info)))) + (desc-file (package--description-file dir-name)) + (tar-desc (tar-get-file-descriptor (concat dir-name desc-file)))) + (unless tar-desc + (error "No package descriptor file found")) + (with-current-buffer (tar--extract tar-desc) + (goto-char (point-min)) + (unwind-protect + (let* ((pkg-def-parsed (read (current-buffer))) + (pkg-desc + (if (not (eq (car pkg-def-parsed) 'define-package)) + (error "Can't find define-package in %s" + (tar-header-name tar-desc)) + (apply #'package-desc-from-define + (append (cdr pkg-def-parsed)))))) + (setf (package-desc-kind pkg-desc) 'tar) + pkg-desc) + (kill-buffer (current-buffer)))))) + + +;;;###autoload +(defun package-install-from-buffer () + "Install a package from the current buffer. +The current buffer is assumed to be a single .el or .tar file that follows the +packaging guidelines; see info node `(elisp)Packaging'. +Downloads and installs required packages as needed." + (interactive) + (let ((pkg-desc (if (derived-mode-p 'tar-mode) + (package-tar-file-info) + (package-buffer-info)))) + ;; Download and install the dependencies. + (let* ((requires (package-desc-reqs pkg-desc)) + (transaction (package-compute-transaction nil requires))) + (package-download-transaction transaction)) + ;; Install the package itself. + (package-unpack pkg-desc) + pkg-desc)) + +;;;###autoload +(defun package-install-file (file) + "Install a package from a file. +The file can either be a tar file or an Emacs Lisp file." + (interactive "fPackage file name: ") + (with-temp-buffer + (insert-file-contents-literally file) + (when (string-match "\\.tar\\'" file) (tar-mode)) + (package-install-from-buffer))) + +(defun package-delete (pkg-desc) + (let ((dir (package-desc-dir pkg-desc))) + (if (not (string-prefix-p (file-name-as-directory + (expand-file-name package-user-dir)) + (expand-file-name dir))) + ;; Don't delete "system" packages. + (error "Package `%s' is a system package, not deleting" + (package-desc-full-name pkg-desc)) + (delete-directory dir t t) + ;; Remove NAME-VERSION.signed file. + (let ((signed-file (concat dir ".signed"))) + (if (file-exists-p signed-file) + (delete-file signed-file))) + ;; Update package-alist. + (let* ((name (package-desc-name pkg-desc)) + (pkgs (assq name package-alist))) + (delete pkg-desc pkgs) + (unless (cdr pkgs) + (setq package-alist (delq pkgs package-alist)))) + (message "Package `%s' deleted." (package-desc-full-name pkg-desc))))) + +(defun package-archive-base (desc) + "Return the archive containing the package NAME." + (cdr (assoc (package-desc-archive desc) package-archives))) + +(defun package--download-one-archive (archive file) + "Retrieve an archive file FILE from ARCHIVE, and cache it. +ARCHIVE should be a cons cell of the form (NAME . LOCATION), +similar to an entry in `package-alist'. Save the cached copy to +\"archives/NAME/archive-contents\" in `package-user-dir'." + (let ((dir (expand-file-name (format "archives/%s" (car archive)) + package-user-dir)) + (sig-file (concat file ".sig")) + good-signatures) + (package--with-work-buffer (cdr archive) file + ;; Check signature of archive-contents, if desired. + (if (and package-check-signature + (not (member archive package-unsigned-archives))) + (if (package--archive-file-exists-p (cdr archive) sig-file) + (setq good-signatures (package--check-signature (cdr archive) + file)) + (unless (eq package-check-signature 'allow-unsigned) + (error "Unsigned archive `%s'" + (car archive))))) + ;; Read the retrieved buffer to make sure it is valid (e.g. it + ;; may fetch a URL redirect page). + (when (listp (read (current-buffer))) + (make-directory dir t) + (write-region nil nil (expand-file-name file dir) nil 'silent))) + (when good-signatures + ;; Write out good signatures into archive-contents.signed file. + (write-region (mapconcat #'epg-signature-to-string good-signatures "\n") + nil + (expand-file-name (concat file ".signed") dir) + nil 'silent)))) + +(declare-function epg-check-configuration "epg-config" + (config &optional minimum-version)) +(declare-function epg-configuration "epg-config" ()) +(declare-function epg-import-keys-from-file "epg" (context keys)) + +;;;###autoload +(defun package-import-keyring (&optional file) + "Import keys from FILE." + (interactive "fFile: ") + (setq file (expand-file-name file)) + (let ((context (epg-make-context 'OpenPGP)) + (homedir (expand-file-name "gnupg" package-user-dir))) + ;; FIXME Use `with-file-modes' when merged to trunk. + (let ((umask (default-file-modes))) + (unwind-protect + (progn + (set-default-file-modes 448) + (make-directory homedir t)) + (set-default-file-modes umask))) + (epg-context-set-home-directory context homedir) + (message "Importing %s..." (file-name-nondirectory file)) + (epg-import-keys-from-file context file) + (message "Importing %s...done" (file-name-nondirectory file)))) + +;;;###autoload +(defun package-refresh-contents () + "Download the ELPA archive description if needed. +This informs Emacs about the latest versions of all packages, and +makes them available for download." + (interactive) + ;; FIXME: Do it asynchronously. + (unless (file-exists-p package-user-dir) + (make-directory package-user-dir t)) + (let ((default-keyring (expand-file-name "package-keyring.gpg" + data-directory))) + (when (and package-check-signature (file-exists-p default-keyring)) + (condition-case-unless-debug error + (progn + (epg-check-configuration (epg-configuration)) + (package-import-keyring default-keyring)) + (error (message "Cannot import default keyring: %S" (cdr error)))))) + (dolist (archive package-archives) + (condition-case-unless-debug nil + (package--download-one-archive archive "archive-contents") + (error (message "Failed to download `%s' archive." + (car archive))))) + (package-read-all-archive-contents)) + +;;;###autoload +(defun package-initialize (&optional no-activate) + "Load Emacs Lisp packages, and activate them. +The variable `package-load-list' controls which packages to load. +If optional arg NO-ACTIVATE is non-nil, don't activate packages." + (interactive) + (setq package-alist nil) + (package-load-all-descriptors) + (package-read-all-archive-contents) + (unless no-activate + (dolist (elt package-alist) + (package-activate (car elt)))) + (setq package--initialized t)) + + +;;;; Package description buffer. + +;;;###autoload +(defun describe-package (package) + "Display the full documentation of PACKAGE (a symbol)." + (interactive + (let* ((guess (function-called-at-point))) + (require 'finder-inf nil t) + ;; Load the package list if necessary (but don't activate them). + (unless package--initialized + (package-initialize t)) + (let ((packages (append (mapcar 'car package-alist) + (mapcar 'car package-archive-contents) + (mapcar 'car package--builtins)))) + (unless (memq guess packages) + (setq guess nil)) + (setq packages (mapcar 'symbol-name packages)) + (let ((val + (completing-read (if guess + (format "Describe package (default %s): " + guess) + "Describe package: ") + packages nil t nil nil guess))) + (list (intern val)))))) + (if (not (or (package-desc-p package) (and package (symbolp package)))) + (message "No package specified") + (help-setup-xref (list #'describe-package package) + (called-interactively-p 'interactive)) + (with-help-window (help-buffer) + (with-current-buffer standard-output + (describe-package-1 package))))) + +(defun describe-package-1 (pkg) + (require 'lisp-mnt) + (let* ((desc (or + (if (package-desc-p pkg) pkg) + (cadr (assq pkg package-alist)) + (let ((built-in (assq pkg package--builtins))) + (if built-in + (package--from-builtin built-in) + (cadr (assq pkg package-archive-contents)))))) + (name (if desc (package-desc-name desc) pkg)) + (pkg-dir (if desc (package-desc-dir desc))) + (reqs (if desc (package-desc-reqs desc))) + (version (if desc (package-desc-version desc))) + (archive (if desc (package-desc-archive desc))) + (extras (and desc (package-desc-extras desc))) + (homepage (cdr (assoc :url extras))) + (keywords (if desc (package-desc--keywords desc))) + (built-in (eq pkg-dir 'builtin)) + (installable (and archive (not built-in))) + (status (if desc (package-desc-status desc) "orphan")) + (signed (if desc (package-desc-signed desc)))) + (prin1 name) + (princ " is ") + (princ (if (memq (aref status 0) '(?a ?e ?i ?o ?u)) "an " "a ")) + (princ status) + (princ " package.\n\n") + + (insert " " (propertize "Status" 'font-lock-face 'bold) ": ") + (cond (built-in + (insert (propertize (capitalize status) + 'font-lock-face 'font-lock-builtin-face) + ".")) + (pkg-dir + (insert (propertize (if (equal status "unsigned") + "Installed" + (capitalize status)) ;FIXME: Why comment-face? + 'font-lock-face 'font-lock-comment-face)) + (insert " in `") + ;; Todo: Add button for uninstalling. + (help-insert-xref-button (abbreviate-file-name + (file-name-as-directory pkg-dir)) + 'help-package-def pkg-dir) + (if (and (package-built-in-p name) + (not (package-built-in-p name version))) + (insert "',\n shadowing a " + (propertize "built-in package" + 'font-lock-face 'font-lock-builtin-face)) + (insert "'")) + (if signed + (insert ".") + (insert " (unsigned)."))) + (installable + (insert (capitalize status)) + (insert " from " (format "%s" archive)) + (insert " -- ") + (package-make-button + "Install" + 'action 'package-install-button-action + 'package-desc desc)) + (t (insert (capitalize status) "."))) + (insert "\n") + (insert " " (propertize "Archive" 'font-lock-face 'bold) + ": " (or archive "n/a") "\n") + (and version + (insert " " + (propertize "Version" 'font-lock-face 'bold) ": " + (package-version-join version) "\n")) + + (setq reqs (if desc (package-desc-reqs desc))) + (when reqs + (insert " " (propertize "Requires" 'font-lock-face 'bold) ": ") + (let ((first t) + name vers text) + (dolist (req reqs) + (setq name (car req) + vers (cadr req) + text (format "%s-%s" (symbol-name name) + (package-version-join vers))) + (cond (first (setq first nil)) + ((>= (+ 2 (current-column) (length text)) + (window-width)) + (insert ",\n ")) + (t (insert ", "))) + (help-insert-xref-button text 'help-package name)) + (insert "\n"))) + (insert " " (propertize "Summary" 'font-lock-face 'bold) + ": " (if desc (package-desc-summary desc)) "\n") + (when homepage + (insert " " (propertize "Homepage" 'font-lock-face 'bold) ": ") + (help-insert-xref-button homepage 'help-url homepage) + (insert "\n")) + (when keywords + (insert " " (propertize "Keywords" 'font-lock-face 'bold) ": ") + (dolist (k keywords) + (package-make-button + k + 'package-keyword k + 'action 'package-keyword-button-action) + (insert " ")) + (insert "\n")) + (let* ((all-pkgs (append (cdr (assq name package-alist)) + (cdr (assq name package-archive-contents)) + (let ((bi (assq name package--builtins))) + (if bi (list (package--from-builtin bi)))))) + (other-pkgs (delete desc all-pkgs))) + (when other-pkgs + (insert " " (propertize "Other versions" 'font-lock-face 'bold) ": " + (mapconcat + (lambda (opkg) + (let* ((ov (package-desc-version opkg)) + (dir (package-desc-dir opkg)) + (from (or (package-desc-archive opkg) + (if (stringp dir) "installed" dir)))) + (if (not ov) (format "%s" from) + (format "%s (%s)" + (make-text-button (package-version-join ov) nil + 'face 'link + 'follow-link t + 'action + (lambda (_button) + (describe-package opkg))) + from)))) + other-pkgs ", ") + ".\n"))) + + (insert "\n") + + (if built-in + ;; For built-in packages, insert the commentary. + (let ((fn (locate-file (format "%s.el" name) load-path + load-file-rep-suffixes)) + (opoint (point))) + (insert (or (lm-commentary fn) "")) + (save-excursion + (goto-char opoint) + (when (re-search-forward "^;;; Commentary:\n" nil t) + (replace-match "")) + (while (re-search-forward "^\\(;+ ?\\)" nil t) + (replace-match "")))) + (let ((readme (expand-file-name (format "%s-readme.txt" name) + package-user-dir)) + readme-string) + ;; For elpa packages, try downloading the commentary. If that + ;; fails, try an existing readme file in `package-user-dir'. + (cond ((condition-case nil + (save-excursion + (package--with-work-buffer + (package-archive-base desc) + (format "%s-readme.txt" name) + (save-excursion + (goto-char (point-max)) + (unless (bolp) + (insert ?\n))) + (write-region nil nil + (expand-file-name readme package-user-dir) + nil 'silent) + (setq readme-string (buffer-string)) + t)) + (error nil)) + (insert readme-string)) + ((file-readable-p readme) + (insert-file-contents readme) + (goto-char (point-max)))))))) + +(defun package-install-button-action (button) + (let ((pkg-desc (button-get button 'package-desc))) + (when (y-or-n-p (format "Install package `%s'? " + (package-desc-full-name pkg-desc))) + (package-install pkg-desc) + (revert-buffer nil t) + (goto-char (point-min))))) + +(defun package-keyword-button-action (button) + (let ((pkg-keyword (button-get button 'package-keyword))) + (package-show-package-list t (list pkg-keyword)))) + +(defun package-make-button (text &rest props) + (let ((button-text (if (display-graphic-p) text (concat "[" text "]"))) + (button-face (if (display-graphic-p) + '(:box (:line-width 2 :color "dark grey") + :background "light grey" + :foreground "black") + 'link))) + (apply 'insert-text-button button-text 'face button-face 'follow-link t + props))) + + +;;;; Package menu mode. + +(defvar package-menu-mode-map + (let ((map (make-sparse-keymap)) + (menu-map (make-sparse-keymap "Package"))) + (set-keymap-parent map tabulated-list-mode-map) + (define-key map "\C-m" 'package-menu-describe-package) + (define-key map "u" 'package-menu-mark-unmark) + (define-key map "\177" 'package-menu-backup-unmark) + (define-key map "d" 'package-menu-mark-delete) + (define-key map "i" 'package-menu-mark-install) + (define-key map "U" 'package-menu-mark-upgrades) + (define-key map "r" 'package-menu-refresh) + (define-key map "f" 'package-menu-filter) + (define-key map "~" 'package-menu-mark-obsolete-for-deletion) + (define-key map "x" 'package-menu-execute) + (define-key map "h" 'package-menu-quick-help) + (define-key map "?" 'package-menu-describe-package) + (define-key map [menu-bar package-menu] (cons "Package" menu-map)) + (define-key menu-map [mq] + '(menu-item "Quit" quit-window + :help "Quit package selection")) + (define-key menu-map [s1] '("--")) + (define-key menu-map [mn] + '(menu-item "Next" next-line + :help "Next Line")) + (define-key menu-map [mp] + '(menu-item "Previous" previous-line + :help "Previous Line")) + (define-key menu-map [s2] '("--")) + (define-key menu-map [mu] + '(menu-item "Unmark" package-menu-mark-unmark + :help "Clear any marks on a package and move to the next line")) + (define-key menu-map [munm] + '(menu-item "Unmark Backwards" package-menu-backup-unmark + :help "Back up one line and clear any marks on that package")) + (define-key menu-map [md] + '(menu-item "Mark for Deletion" package-menu-mark-delete + :help "Mark a package for deletion and move to the next line")) + (define-key menu-map [mi] + '(menu-item "Mark for Install" package-menu-mark-install + :help "Mark a package for installation and move to the next line")) + (define-key menu-map [mupgrades] + '(menu-item "Mark Upgradable Packages" package-menu-mark-upgrades + :help "Mark packages that have a newer version for upgrading")) + (define-key menu-map [s3] '("--")) + (define-key menu-map [mf] + '(menu-item "Filter Package List..." package-menu-filter + :help "Filter package selection (q to go back)")) + (define-key menu-map [mg] + '(menu-item "Update Package List" revert-buffer + :help "Update the list of packages")) + (define-key menu-map [mr] + '(menu-item "Refresh Package List" package-menu-refresh + :help "Download the ELPA archive")) + (define-key menu-map [s4] '("--")) + (define-key menu-map [mt] + '(menu-item "Mark Obsolete Packages" package-menu-mark-obsolete-for-deletion + :help "Mark all obsolete packages for deletion")) + (define-key menu-map [mx] + '(menu-item "Execute Actions" package-menu-execute + :help "Perform all the marked actions")) + (define-key menu-map [s5] '("--")) + (define-key menu-map [mh] + '(menu-item "Help" package-menu-quick-help + :help "Show short key binding help for package-menu-mode")) + (define-key menu-map [mc] + '(menu-item "Describe Package" package-menu-describe-package + :help "Display information about this package")) + map) + "Local keymap for `package-menu-mode' buffers.") + +(defvar package-menu--new-package-list nil + "List of newly-available packages since `list-packages' was last called.") + +(define-derived-mode package-menu-mode tabulated-list-mode "Package Menu" + "Major mode for browsing a list of packages. +Letters do not insert themselves; instead, they are commands. +\\ +\\{package-menu-mode-map}" + (setq tabulated-list-format + `[("Package" 18 package-menu--name-predicate) + ("Version" 12 nil) + ("Status" 10 package-menu--status-predicate) + ,@(if (cdr package-archives) + '(("Archive" 10 package-menu--archive-predicate))) + ("Description" 0 nil)]) + (setq tabulated-list-padding 2) + (setq tabulated-list-sort-key (cons "Status" nil)) + (add-hook 'tabulated-list-revert-hook 'package-menu--refresh nil t) + (tabulated-list-init-header)) + +(defmacro package--push (pkg-desc status listname) + "Convenience macro for `package-menu--generate'. +If the alist stored in the symbol LISTNAME lacks an entry for a +package PKG-DESC, add one. The alist is keyed with PKG-DESC." + `(unless (assoc ,pkg-desc ,listname) + ;; FIXME: Should we move status into pkg-desc? + (push (cons ,pkg-desc ,status) ,listname))) + +(defvar package-list-unversioned nil + "If non-nil include packages that don't have a version in `list-package'.") + +(defvar package-list-unsigned nil + "If non-nil, mention in the list which packages were installed w/o signature.") + +(defun package-desc-status (pkg-desc) + (let* ((name (package-desc-name pkg-desc)) + (dir (package-desc-dir pkg-desc)) + (lle (assq name package-load-list)) + (held (cadr lle)) + (version (package-desc-version pkg-desc)) + (signed (package-desc-signed pkg-desc))) + (cond + ((eq dir 'builtin) "built-in") + ((and lle (null held)) "disabled") + ((stringp held) + (let ((hv (if (stringp held) (version-to-list held)))) + (cond + ((version-list-= version hv) "held") + ((version-list-< version hv) "obsolete") + (t "disabled")))) + ((package-built-in-p name version) "obsolete") + (dir ;One of the installed packages. + (cond + ((not (file-exists-p (package-desc-dir pkg-desc))) "deleted") + ((eq pkg-desc (cadr (assq name package-alist))) + (if (or (not package-list-unsigned) signed) "installed" "unsigned")) + (t "obsolete"))) + (t + (let* ((ins (cadr (assq name package-alist))) + (ins-v (if ins (package-desc-version ins)))) + (cond + ((or (null ins) (version-list-< ins-v version)) + (if (memq name package-menu--new-package-list) + "new" "available")) + ((version-list-< version ins-v) "obsolete") + ((version-list-= version ins-v) + (if (or (not package-list-unsigned) signed) + "installed" "unsigned")))))))) + +(defun package-menu--refresh (&optional packages keywords) + "Re-populate the `tabulated-list-entries'. +PACKAGES should be nil or t, which means to display all known packages. +KEYWORDS should be nil or a list of keywords." + ;; Construct list of (PKG-DESC . STATUS). + (unless packages (setq packages t)) + (let (info-list name) + ;; Installed packages: + (dolist (elt package-alist) + (setq name (car elt)) + (when (or (eq packages t) (memq name packages)) + (dolist (pkg (cdr elt)) + (when (package--has-keyword-p pkg keywords) + (package--push pkg (package-desc-status pkg) info-list))))) + + ;; Built-in packages: + (dolist (elt package--builtins) + (setq name (car elt)) + (when (and (not (eq name 'emacs)) ; Hide the `emacs' package. + (package--has-keyword-p (package--from-builtin elt) keywords) + (or package-list-unversioned + (package--bi-desc-version (cdr elt))) + (or (eq packages t) (memq name packages))) + (package--push (package--from-builtin elt) "built-in" info-list))) + + ;; Available and disabled packages: + (dolist (elt package-archive-contents) + (setq name (car elt)) + (when (or (eq packages t) (memq name packages)) + (dolist (pkg (cdr elt)) + ;; Hide obsolete packages. + (when (and (not (package-installed-p (package-desc-name pkg) + (package-desc-version pkg))) + (package--has-keyword-p pkg keywords)) + (package--push pkg (package-desc-status pkg) info-list))))) + + ;; Print the result. + (setq tabulated-list-entries + (mapcar #'package-menu--print-info info-list)))) + +(defun package-all-keywords () + "Collect all package keywords" + (let (keywords) + (package--mapc (lambda (desc) + (let* ((desc-keywords (and desc (package-desc--keywords desc)))) + (setq keywords (append keywords desc-keywords))))) + keywords)) + +(defun package--mapc (function &optional packages) + "Call FUNCTION for all known PACKAGES. +PACKAGES can be nil or t, which means to display all known +packages, or a list of packages. + +Built-in packages are converted with `package--from-builtin'." + (unless packages (setq packages t)) + (let (name) + ;; Installed packages: + (dolist (elt package-alist) + (setq name (car elt)) + (when (or (eq packages t) (memq name packages)) + (mapc function (cdr elt)))) + + ;; Built-in packages: + (dolist (elt package--builtins) + (setq name (car elt)) + (when (and (not (eq name 'emacs)) ; Hide the `emacs' package. + (or package-list-unversioned + (package--bi-desc-version (cdr elt))) + (or (eq packages t) (memq name packages))) + (funcall function (package--from-builtin elt)))) + + ;; Available and disabled packages: + (dolist (elt package-archive-contents) + (setq name (car elt)) + (when (or (eq packages t) (memq name packages)) + (dolist (pkg (cdr elt)) + ;; Hide obsolete packages. + (unless (package-installed-p (package-desc-name pkg) + (package-desc-version pkg)) + (funcall function pkg))))))) + +(defun package--has-keyword-p (desc &optional keywords) + "Test if package DESC has any of the given KEYWORDS. +When none are given, the package matches." + (if keywords + (let* ((desc-keywords (and desc (package-desc--keywords desc))) + found) + (dolist (k keywords) + (when (and (not found) + (member k desc-keywords)) + (setq found t))) + found) + t)) + +(defun package-menu--generate (remember-pos packages &optional keywords) + "Populate the Package Menu. + If REMEMBER-POS is non-nil, keep point on the same entry. +PACKAGES should be t, which means to display all known packages, +or a list of package names (symbols) to display. + +With KEYWORDS given, only packages with those keywords are +shown." + (package-menu--refresh packages keywords) + (setf (car (aref tabulated-list-format 0)) + (if keywords + (let ((filters (mapconcat 'identity keywords ","))) + (concat "Package[" filters "]")) + "Package")) + (if keywords + (define-key package-menu-mode-map "q" 'package-show-package-list) + (define-key package-menu-mode-map "q" 'quit-window)) + (tabulated-list-init-header) + (tabulated-list-print remember-pos)) + +(defun package-menu--print-info (pkg) + "Return a package entry suitable for `tabulated-list-entries'. +PKG has the form (PKG-DESC . STATUS). +Return (PKG-DESC [NAME VERSION STATUS DOC])." + (let* ((pkg-desc (car pkg)) + (status (cdr pkg)) + (face (pcase status + (`"built-in" 'font-lock-builtin-face) + (`"available" 'default) + (`"new" 'bold) + (`"held" 'font-lock-constant-face) + (`"disabled" 'font-lock-warning-face) + (`"installed" 'font-lock-comment-face) + (`"unsigned" 'font-lock-warning-face) + (_ 'font-lock-warning-face)))) ; obsolete. + (list pkg-desc + `[,(list (symbol-name (package-desc-name pkg-desc)) + 'face 'link + 'follow-link t + 'package-desc pkg-desc + 'action 'package-menu-describe-package) + ,(propertize (package-version-join + (package-desc-version pkg-desc)) + 'font-lock-face face) + ,(propertize status 'font-lock-face face) + ,@(if (cdr package-archives) + (list (propertize (or (package-desc-archive pkg-desc) "") + 'font-lock-face face))) + ,(propertize (package-desc-summary pkg-desc) + 'font-lock-face face)]))) + +(defun package-menu-refresh () + "Download the Emacs Lisp package archive. +This fetches the contents of each archive specified in +`package-archives', and then refreshes the package menu." + (interactive) + (unless (derived-mode-p 'package-menu-mode) + (user-error "The current buffer is not a Package Menu")) + (package-refresh-contents) + (package-menu--generate t t)) + +(defun package-menu-describe-package (&optional button) + "Describe the current package. +If optional arg BUTTON is non-nil, describe its associated package." + (interactive) + (let ((pkg-desc (if button (button-get button 'package-desc) + (tabulated-list-get-id)))) + (if pkg-desc + (describe-package pkg-desc) + (user-error "No package here")))) + +;; fixme numeric argument +(defun package-menu-mark-delete (&optional _num) + "Mark a package for deletion and move to the next line." + (interactive "p") + (if (member (package-menu-get-status) '("installed" "obsolete" "unsigned")) + (tabulated-list-put-tag "D" t) + (forward-line))) + +(defun package-menu-mark-install (&optional _num) + "Mark a package for installation and move to the next line." + (interactive "p") + (if (member (package-menu-get-status) '("available" "new")) + (tabulated-list-put-tag "I" t) + (forward-line))) + +(defun package-menu-mark-unmark (&optional _num) + "Clear any marks on a package and move to the next line." + (interactive "p") + (tabulated-list-put-tag " " t)) + +(defun package-menu-backup-unmark () + "Back up one line and clear any marks on that package." + (interactive) + (forward-line -1) + (tabulated-list-put-tag " ")) + +(defun package-menu-mark-obsolete-for-deletion () + "Mark all obsolete packages for deletion." + (interactive) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (if (equal (package-menu-get-status) "obsolete") + (tabulated-list-put-tag "D" t) + (forward-line 1))))) + +(defun package-menu-quick-help () + "Show short key binding help for package-menu-mode." + (interactive) + (message "n-ext, i-nstall, d-elete, u-nmark, x-ecute, r-efresh, h-elp")) + +(define-obsolete-function-alias + 'package-menu-view-commentary 'package-menu-describe-package "24.1") + +(defun package-menu-get-status () + (let* ((id (tabulated-list-get-id)) + (entry (and id (assq id tabulated-list-entries)))) + (if entry + (aref (cadr entry) 2) + ""))) + +(defun package-menu--find-upgrades () + (let (installed available upgrades) + ;; Build list of installed/available packages in this buffer. + (dolist (entry tabulated-list-entries) + ;; ENTRY is (PKG-DESC [NAME VERSION STATUS DOC]) + (let ((pkg-desc (car entry)) + (status (aref (cadr entry) 2))) + (cond ((member status '("installed" "unsigned")) + (push pkg-desc installed)) + ((member status '("available" "new")) + (push (cons (package-desc-name pkg-desc) pkg-desc) + available))))) + ;; Loop through list of installed packages, finding upgrades. + (dolist (pkg-desc installed) + (let ((avail-pkg (assq (package-desc-name pkg-desc) available))) + (and avail-pkg + (version-list-< (package-desc-version pkg-desc) + (package-desc-version (cdr avail-pkg))) + (push avail-pkg upgrades)))) + upgrades)) + +(defun package-menu-mark-upgrades () + "Mark all upgradable packages in the Package Menu. +For each installed package with a newer version available, place +an (I)nstall flag on the available version and a (D)elete flag on +the installed version. A subsequent \\[package-menu-execute] +call will upgrade the package." + (interactive) + (unless (derived-mode-p 'package-menu-mode) + (error "The current buffer is not a Package Menu")) + (let ((upgrades (package-menu--find-upgrades))) + (if (null upgrades) + (message "No packages to upgrade.") + (widen) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (let* ((pkg-desc (tabulated-list-get-id)) + (upgrade (cdr (assq (package-desc-name pkg-desc) upgrades)))) + (cond ((null upgrade) + (forward-line 1)) + ((equal pkg-desc upgrade) + (package-menu-mark-install)) + (t + (package-menu-mark-delete)))))) + (message "%d package%s marked for upgrading." + (length upgrades) + (if (= (length upgrades) 1) "" "s"))))) + +(defun package-menu-execute (&optional noquery) + "Perform marked Package Menu actions. +Packages marked for installation are downloaded and installed; +packages marked for deletion are removed. +Optional argument NOQUERY non-nil means do not ask the user to confirm." + (interactive) + (unless (derived-mode-p 'package-menu-mode) + (error "The current buffer is not in Package Menu mode")) + (let (install-list delete-list cmd pkg-desc) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (setq cmd (char-after)) + (unless (eq cmd ?\s) + ;; This is the key PKG-DESC. + (setq pkg-desc (tabulated-list-get-id)) + (cond ((eq cmd ?D) + (push pkg-desc delete-list)) + ((eq cmd ?I) + (push pkg-desc install-list)))) + (forward-line))) + (when install-list + (if (or + noquery + (yes-or-no-p + (if (= (length install-list) 1) + (format "Install package `%s'? " + (package-desc-full-name (car install-list))) + (format "Install these %d packages (%s)? " + (length install-list) + (mapconcat #'package-desc-full-name + install-list ", "))))) + (mapc 'package-install install-list))) + ;; Delete packages, prompting if necessary. + (when delete-list + (if (or + noquery + (yes-or-no-p + (if (= (length delete-list) 1) + (format "Delete package `%s'? " + (package-desc-full-name (car delete-list))) + (format "Delete these %d packages (%s)? " + (length delete-list) + (mapconcat #'package-desc-full-name + delete-list ", "))))) + (dolist (elt delete-list) + (condition-case-unless-debug err + (package-delete elt) + (error (message (cadr err))))) + (error "Aborted"))) + (if (or delete-list install-list) + (package-menu--generate t t) + (message "No operations specified.")))) + +(defun package-menu--version-predicate (A B) + (let ((vA (or (aref (cadr A) 1) '(0))) + (vB (or (aref (cadr B) 1) '(0)))) + (if (version-list-= vA vB) + (package-menu--name-predicate A B) + (version-list-< vA vB)))) + +(defun package-menu--status-predicate (A B) + (let ((sA (aref (cadr A) 2)) + (sB (aref (cadr B) 2))) + (cond ((string= sA sB) + (package-menu--name-predicate A B)) + ((string= sA "new") t) + ((string= sB "new") nil) + ((string= sA "available") t) + ((string= sB "available") nil) + ((string= sA "installed") t) + ((string= sB "installed") nil) + ((string= sA "unsigned") t) + ((string= sB "unsigned") nil) + ((string= sA "held") t) + ((string= sB "held") nil) + ((string= sA "built-in") t) + ((string= sB "built-in") nil) + ((string= sA "obsolete") t) + ((string= sB "obsolete") nil) + (t (string< sA sB))))) + +(defun package-menu--description-predicate (A B) + (let ((dA (aref (cadr A) 3)) + (dB (aref (cadr B) 3))) + (if (string= dA dB) + (package-menu--name-predicate A B) + (string< dA dB)))) + +(defun package-menu--name-predicate (A B) + (string< (symbol-name (package-desc-name (car A))) + (symbol-name (package-desc-name (car B))))) + +(defun package-menu--archive-predicate (A B) + (string< (or (package-desc-archive (car A)) "") + (or (package-desc-archive (car B)) ""))) + +;;;###autoload +(defun list-packages (&optional no-fetch) + "Display a list of packages. +This first fetches the updated list of packages before +displaying, unless a prefix argument NO-FETCH is specified. +The list is displayed in a buffer named `*Packages*'." + (interactive "P") + (require 'finder-inf nil t) + ;; Initialize the package system if necessary. + (unless package--initialized + (package-initialize t)) + (let (old-archives new-packages) + (unless no-fetch + ;; Read the locally-cached archive-contents. + (package-read-all-archive-contents) + (setq old-archives package-archive-contents) + ;; Fetch the remote list of packages. + (package-refresh-contents) + ;; Find which packages are new. + (dolist (elt package-archive-contents) + (unless (assq (car elt) old-archives) + (push (car elt) new-packages)))) + + ;; Generate the Package Menu. + (let ((buf (get-buffer-create "*Packages*"))) + (with-current-buffer buf + (package-menu-mode) + (set (make-local-variable 'package-menu--new-package-list) + new-packages) + (package-menu--generate nil t)) + ;; The package menu buffer has keybindings. If the user types + ;; `M-x list-packages', that suggests it should become current. + (switch-to-buffer buf)) + + (let ((upgrades (package-menu--find-upgrades))) + (if upgrades + (message "%d package%s can be upgraded; type `%s' to mark %s for upgrading." + (length upgrades) + (if (= (length upgrades) 1) "" "s") + (substitute-command-keys "\\[package-menu-mark-upgrades]") + (if (= (length upgrades) 1) "it" "them")))))) + +;;;###autoload +(defalias 'package-list-packages 'list-packages) + +;; Used in finder.el +(defun package-show-package-list (&optional packages keywords) + "Display PACKAGES in a *Packages* buffer. +This is similar to `list-packages', but it does not fetch the +updated list of packages, and it only displays packages with +names in PACKAGES (which should be a list of symbols). + +When KEYWORDS are given, only packages with those KEYWORDS are +shown." + (interactive) + (require 'finder-inf nil t) + (let* ((buf (get-buffer-create "*Packages*")) + (win (get-buffer-window buf))) + (with-current-buffer buf + (package-menu-mode) + (package-menu--generate nil packages keywords)) + (if win + (select-window win) + (switch-to-buffer buf)))) + +;; package-menu--generate rebinds "q" on the fly, so we have to +;; hard-code the binding in the doc-string here. +(defun package-menu-filter (keyword) + "Filter the *Packages* buffer. +Show only those items that relate to the specified KEYWORD. +To restore the full package list, type `q'." + (interactive (list (completing-read "Keyword: " (package-all-keywords)))) + (package-show-package-list t (list keyword))) + +(defun package-list-packages-no-fetch () + "Display a list of packages. +Does not fetch the updated list of packages before displaying. +The list is displayed in a buffer named `*Packages*'." + (interactive) + (list-packages t)) + +(provide 'package) + +;;; package.el ends here diff --git a/lisp/prolog.el b/lisp/prolog.el new file mode 100644 index 0000000..82b707f --- /dev/null +++ b/lisp/prolog.el @@ -0,0 +1,4143 @@ +;; prolog.el --- major mode for editing and running Prolog (and Mercury) code + +;; Copyright (C) 1986, 1987, 1997, 1998, 1999, 2002, 2003 Free Software Foundation, Inc. + +;; Authors: Emil Åström +;; Milan Zamazal +;; Stefan Bruda (current maintainer) +;; * See below for more details +;; Keywords: prolog major mode sicstus swi mercury + +(defvar prolog-mode-version "1.23" + "Prolog mode version number") + +;; 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, 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; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;; Original author: Masanobu UMEDA +;; Parts of this file was taken from a modified version of the original +;; by Johan Andersson, Peter Olin, Mats Carlsson, Johan Bevemyr, Stefan +;; Andersson, and Per Danielsson (all SICS people), and Henrik Båkman +;; at Uppsala University, Sweden. +;; +;; Some ideas and also a few lines of code have been borrowed (not stolen ;-) +;; from Oz.el, the Emacs major mode for the Oz programming language, +;; Copyright (C) 1993 DFKI GmbH, Germany, with permission. +;; Authors: Ralf Scheidhauer and Michael Mehl ([scheidhr|mehl](at)dfki(dot)uni-sb(dot)de) +;; +;; More ideas and code have been taken from the SICStus debugger mode +;; (http://www.csd.uu.se/~perm/source_debug/index.shtml -- broken link +;; as of Mon May 5 08:23:48 EDT 2003) by Per Mildner. +;; +;; Additions for ECLiPSe and other helpful suggestions: Stephan Heuel +;; + +;;; Commentary: +;; +;; This package provides a major mode for editing Prolog code, with +;; all the bells and whistles one would expect, including syntax +;; highlighting and auto indentation. It can also send regions to an +;; inferior Prolog process. +;; +;; The code requires the comint, easymenu, info, imenu, and font-lock +;; libraries. These are normally distributed with GNU Emacs and +;; XEmacs. + +;;; Installation: +;; +;; Insert the following lines in your init file--typically ~/.emacs +;; (GNU Emacs and XEmacs <21.4), or ~/.xemacs/init.el (XEmacs +;; 21.4)--to use this mode when editing Prolog files under Emacs: +;; +;; (setq load-path (cons "/usr/lib/xemacs/site-lisp" load-path)) +;; (autoload 'run-prolog "prolog" "Start a Prolog sub-process." t) +;; (autoload 'prolog-mode "prolog" "Major mode for editing Prolog programs." t) +;; (autoload 'mercury-mode "prolog" "Major mode for editing Mercury programs." t) +;; (setq prolog-system 'swi) ; optional, the system you are using; +;; ; see `prolog-system' below for possible values +;; (setq auto-mode-alist (append '(("\\.pl$" . prolog-mode) +;; ("\\.m$" . mercury-mode)) +;; auto-mode-alist)) +;; +;; where the path in the first line is the file system path to this file. +;; MSDOS paths can be written like "d:/programs/emacs-19.34/site-lisp". +;; Note: In XEmacs, either `/usr/lib/xemacs/site-lisp' (RPM default in +;; Red Hat-based distributions) or `/usr/local/lib/xemacs/site-lisp' +;; (default when compiling from sources) are automatically added to +;; `load-path', so the first line is not necessary provided that you +;; put this file in the appropriate place. +;; +;; The last s-expression above makes sure that files ending with .pl +;; are assumed to be Prolog files and not Perl, which is the default +;; Emacs setting. If this is not wanted, remove this line. It is then +;; necessary to either +;; +;; o insert in your Prolog files the following comment as the first line: +;; +;; % -*- Mode: Prolog -*- +;; +;; and then the file will be open in Prolog mode no matter its +;; extension, or +;; +;; o manually switch to prolog mode after opening a Prolog file, by typing +;; M-x prolog-mode. +;; +;; If the command to start the prolog process ('sicstus', 'pl' or +;; 'swipl' for SWI prolog, etc.) is not available in the default path, +;; then it is necessary to set the value of the environment variable +;; EPROLOG to a shell command to invoke the prolog process. In XEmacs +;; and Emacs 20+ you can also customize the variable +;; `prolog-program-name' (in the group `prolog-inferior') and provide +;; a full path for your Prolog system (swi, scitus, etc.). +;; +;; Note: I (Stefan, the current maintainer) work under XEmacs. Future +;; developments will thus be biased towards XEmacs (OK, I admit it, +;; I am biased towards XEmacs in general), though I will do my best +;; to keep the GNU Emacs compatibility. So if you work under Emacs +;; and see something that does not work do drop me a line, as I have +;; a smaller chance to notice this kind of bugs otherwise. + +;; Changelog: + +;; Version 1.23: +;; o Added support for XSB ; trivial +;; adaptation of a patch by Spyros Hadjichristodoulou and Cosmin +;; Munteanu +;; Version 1.22: +;; o Allowed both 'swipl' and 'pl' as names for the SWI Prolog +;; interpreter. +;; o Atoms that start a line are not blindly coloured as +;; predicates. Instead we check that they are followed by ( or +;; :- first. Patch suggested by Guy Wiener. +;; Version 1.21: +;; o Cleaned up the code that defines faces. The missing face +;; warnings on some Emacsen should disappear. +;; Version 1.20: +;; o Improved the handling of clause start detection and multi-line +;; comments: `prolog-clause-start' no longer finds non-predicate +;; (e.g., capitalized strings) beginning of clauses. +;; `prolog-tokenize' recognizes when the end point is within a +;; multi-line comment. +;; Version 1.19: +;; o Minimal changes for Aquamacs inclusion and in general for +;; better coping with finding the Prolog executable. Patch +;; provided by David Reitter +;; Version 1.18: +;; o Fixed syntax highlighting for clause heads that do not begin at +;; the beginning of the line. +;; o Fixed compilation warnings under Emacs. +;; o Updated the email address of the current maintainer. +;; Version 1.17: +;; o Minor indentation fix (patch by Markus Triska) +;; o `prolog-underscore-wordchar-flag' defaults now to nil (more +;; consistent to other Emacs modes) +;; Version 1.16: +;; o Eliminated a possible compilation warning. +;; Version 1.15: +;; o Introduced three new customizable variables: electric colon +;; (`prolog-electric-colon-flag', default nil), electric dash +;; (`prolog-electric-dash-flag', default nil), and a possibility +;; to prevent the predicate template insertion from adding commata +;; (`prolog-electric-dot-full-predicate-template', defaults to t +;; since it seems quicker to me to just type those commata). A +;; trivial adaptation of a patch by Markus Triska. +;; o Improved the behaviour of electric if-then-else to only skip +;; forward if the parenthesis/semicolon is preceded by +;; whitespace. Once more a trivial adaptation of a patch by +;; Markus Triska. +;; Version 1.14: +;; o Cleaned up align code. `prolog-align-flag' is eliminated (since +;; on a second thought it does not do anything useful). Added key +;; binding (C-c C-a) and menu entry for alignment. +;; o Condensed regular expressions for lower and upper case +;; characters (GNU Emacs seems to go over the regexp length limit +;; with the original form). My code on the matter was improved +;; considerably by Markus Triska. +;; o Fixed `prolog-insert-spaces-after-paren' (which used an +;; unitialized variable). +;; o Minor changes to clean up the code and avoid some implicit +;; package requirements. +;; Version 1.13: +;; o Removed the use of `map-char-table' in `prolog-build-case-strings' +;; which appears to cause prblems in (at least) Emacs 23.0.0.1. +;; o Added if-then-else indentation + corresponding electric +;; characters. New customization: `prolog-electric-if-then-else-flag' +;; o Align support (requires `align'). New customization: +;; `prolog-align-flag'. +;; o Temporary consult files have now the same name throughout the +;; session. This prevents issues with reconsulting a buffer +;; (this event is no longer passed to Prolog as a request to +;; consult a new file). +;; o Adaptive fill mode is now turned on. Comment indentation is +;; still worse than it could be though, I am working on it. +;; o Improved filling and auto-filling capabilities. Now block +;; comments should be [auto-]filled correctly most of the time; +;; the following pattern in particular is worth noting as being +;; filled correctly: +;; % some comment here that goes beyond the +;; % rightmost column, possibly combined with +;; % subsequent comment lines +;; o `prolog-char-quote-workaround' now defaults to nil. +;; o Note: Many of the above improvements have been suggested by +;; Markus Triska, who also provided useful patches on the matter +;; when he realized that I was slow in responding. Many thanks. +;; Version 1.11 / 1.12 +;; o GNU Emacs compatibility fix for paragraph filling (fixed +;; incorrectly in 1.11, fix fixed in 1.12). +;; Version 1.10 +;; o Added paragraph filling in comment blocks and also correct auto +;; filling for comments. +;; o Fixed the possible "Regular expression too big" error in +;; `prolog-electric-dot'. +;; Version 1.9 +;; o Parenthesis expressions are now indented by default so that +;; components go one underneath the other, just as for compound +;; terms. You can use the old style (the second and subsequent +;; lines being indented to the right in a parenthesis expression) +;; by setting the customizable variable `prolog-paren-indent-p' +;; (group "Prolog Indentation") to t. +;; o (Somehow awkward) handling of the 0' character escape +;; sequence. I am looking into a better way of doing it but +;; prospects look bleak. If this breaks things for you please let +;; me know and also set the `prolog-char-quote-workaround' (group +;; "Prolog Other") to nil. +;; Version 1.8 +;; o Key binding fix. +;; Version 1.7 +;; o Fixed a number of issues with the syntax of single quotes, +;; including Debian bug #324520. +;; Version 1.6 +;; o Fixed mercury mode menu initialization (Debian bug #226121). +;; o Fixed (i.e., eliminated) Delete remapping (Debian bug #229636). +;; o Corrected indentation for clauses defining quoted atoms. +;; Version 1.5: +;; o Keywords fontifying should work in console mode so this is +;; enabled everywhere. +;; Version 1.4: +;; o Now supports GNU Prolog--minor adaptation of a patch by Stefan +;; Moeding. +;; Version 1.3: +;; o Info-follow-nearest-node now called correctly under Emacs too +;; (thanks to Nicolas Pelletier). Should be implemented more +;; elegantly (i.e., without compilation warnings) in the future. +;; Version 1.2: +;; o Another prompt fix, still in SWI mode (people seem to have +;; changed the prompt of SWI Prolog). +;; Version 1.1: +;; o Fixed dots in the end of line comments causing indentation +;; problems. The following code is now correctly indented (note +;; the dot terminating the comment): +;; a(X) :- b(X), +;; c(X). % comment here. +;; a(X). +;; and so is this (and variants): +;; a(X) :- b(X), +;; c(X). /* comment here. */ +;; a(X). +;; Version 1.0: +;; o Revamped the menu system. +;; o Yet another prompt recognition fix (SWI mode). +;; o This is more of a renumbering than a new edition. I promoted +;; the mode to version 1.0 to emphasize the fact that it is now +;; mature and stable enough to be considered production (in my +;; opinion anyway). +;; Version 0.1.41: +;; o GNU Emacs compatibility fixes. +;; Version 0.1.40: +;; o prolog-get-predspec is now suitable to be called as +;; imenu-extract-index-name-function. The predicate index works. +;; o Since imenu works now as advertised, prolog-imenu-flag is t +;; by default. +;; o Eliminated prolog-create-predicate-index since the imenu +;; utilities now work well. Actually, this function is also +;; buggy, and I see no reason to fix it since we do not need it +;; anyway. +;; o Fixed prolog-pred-start, prolog-clause-start, prolog-clause-info. +;; o Fix for prolog-build-case-strings; now prolog-upper-case-string +;; and prolog-lower-case-string are correctly initialized, +;; o Various font-lock changes; most importantly, block comments (/* +;; ... */) are now correctly fontified in XEmacs even when they +;; extend on multiple lines. +;; Version 0.1.36: +;; o The debug prompt of SWI Prolog is now correctly recognized. +;; Version 0.1.35: +;; o Minor font-lock bug fixes. + + +;;; Code: + +(eval-when-compile + (require 'compile) + (require 'font-lock) + ;; We need imenu everywhere because of the predicate index! + (require 'imenu) + ;) + (require 'info) + (require 'shell) + ) + +(require 'comint) +(require 'easymenu) +(require 'align) + + +(defgroup prolog nil + "Major modes for editing and running Prolog and Mercury files." + :group 'languages) + +(defgroup prolog-faces nil + "Prolog mode specific faces." + :group 'font-lock) + +(defgroup prolog-indentation nil + "Prolog mode indentation configuration." + :group 'prolog) + +(defgroup prolog-font-lock nil + "Prolog mode font locking patterns." + :group 'prolog) + +(defgroup prolog-keyboard nil + "Prolog mode keyboard flags." + :group 'prolog) + +(defgroup prolog-inferior nil + "Inferior Prolog mode options." + :group 'prolog) + +(defgroup prolog-other nil + "Other Prolog mode options." + :group 'prolog) + + +;;------------------------------------------------------------------- +;; User configurable variables +;;------------------------------------------------------------------- + +;; General configuration + +(defcustom prolog-system nil + "*Prolog interpreter/compiler used. +The value of this variable is nil or a symbol. +If it is a symbol, it determines default values of other configuration +variables with respect to properties of the specified Prolog +interpreter/compiler. + +Currently recognized symbol values are: +eclipse - Eclipse Prolog +mercury - Mercury +sicstus - SICStus Prolog +swi - SWI Prolog +xsb - XSB +gnu - GNU Prolog" + :group 'prolog + :type '(choice (const :tag "SICStus" :value sicstus) + (const :tag "SWI Prolog" :value swi) + (const :tag "Default" :value nil))) +(make-variable-buffer-local 'prolog-system) + +;; NB: This alist can not be processed in prolog-mode-variables to +;; create a prolog-system-version-i variable since it is needed +;; prior to the call to prolog-mode-variables. +(defcustom prolog-system-version + '((sicstus (3 . 6)) + (swi (0 . 0)) + (mercury (0 . 0)) + (eclipse (3 . 7)) + (gnu (0 . 0))) + "*Alist of Prolog system versions. +The version numbers are of the format (Major . Minor)." + :group 'prolog) + +;; Indentation + +(defcustom prolog-indent-width tab-width + "*The indentation width used by the editing buffer." + :group 'prolog-indentation + :type 'integer) + +(defcustom prolog-align-comments-flag t + "*Non-nil means automatically align comments when indenting." + :group 'prolog-indentation + :type 'boolean) + +(defcustom prolog-indent-mline-comments-flag t + "*Non-nil means indent contents of /* */ comments. +Otherwise leave such lines as they are." + :group 'prolog-indentation + :type 'boolean) + +(defcustom prolog-object-end-to-0-flag t + "*Non-nil means indent closing '}' in SICStus object definitions to level 0. +Otherwise indent to `prolog-indent-width'." + :group 'prolog-indentation + :type 'boolean) + +(defcustom prolog-left-indent-regexp "\\(;\\|\\*?->\\)" + "*Regexp for character sequences after which next line is indented. +Next line after such a regexp is indented to the opening paranthesis level." + :group 'prolog-indentation + :type 'regexp) + +(defcustom prolog-paren-indent-p nil + "*If non-nil, increase indentation for parenthesis expressions. +The second and subsequent line in a parenthesis expression other than +a compound term can either be indented `prolog-paren-indent' to the +right (if this variable is non-nil) or in the same way as for compound +terms (if this variable is nil, default)." + :group 'prolog-indentation + :type 'boolean) + +(defcustom prolog-paren-indent 4 + "*The indentation increase for parenthesis expressions. +Only used in ( If -> Then ; Else) and ( Disj1 ; Disj2 ) style expressions." + :group 'prolog-indentation + :type 'integer) + +(defcustom prolog-parse-mode 'beg-of-clause + "*The parse mode used (decides from which point parsing is done). +Legal values: +'beg-of-line - starts parsing at the beginning of a line, unless the + previous line ends with a backslash. Fast, but has + problems detecting multiline /* */ comments. +'beg-of-clause - starts parsing at the beginning of the current clause. + Slow, but copes better with /* */ comments." + :group 'prolog-indentation + :type '(choice (const :value beg-of-line) + (const :value beg-of-clause))) + +;; Font locking + +(defcustom prolog-keywords + '((eclipse + ("use_module" "begin_module" "module_interface" "dynamic" + "external" "export" "dbgcomp" "nodbgcomp" "compile")) + (mercury + ("all" "else" "end_module" "equality" "external" "fail" "func" "if" + "implementation" "import_module" "include_module" "inst" "instance" + "interface" "mode" "module" "not" "pragma" "pred" "some" "then" "true" + "type" "typeclass" "use_module" "where")) + (sicstus + ("block" "dynamic" "mode" "module" "multifile" "meta_predicate" + "parallel" "public" "sequential" "volatile")) + (swi + ("discontiguous" "dynamic" "ensure_loaded" "export" "export_list" "import" + "meta_predicate" "module" "module_transparent" "multifile" "require" + "use_module" "volatile")) + (gnu + ("built_in" "char_conversion" "discontiguous" "dynamic" "ensure_linked" + "ensure_loaded" "foreign" "include" "initialization" "multifile" "op" + "public" "set_prolog_flag")) + (xsb + ("dynamic" "import" "export" "from" "table" "auto_table" "ti" "multifile" + "true" "fail")) + (t + ("dynamic" "module"))) + "*Alist of Prolog keywords which is used for font locking of directives." + :group 'prolog-font-lock + :type 'sexp) + +(defcustom prolog-types + '((mercury + ("char" "float" "int" "io__state" "string" "univ")) + (t nil)) + "*Alist of Prolog types used by font locking." + :group 'prolog-font-lock + :type 'sexp) + +(defcustom prolog-mode-specificators + '((mercury + ("bound" "di" "free" "ground" "in" "mdi" "mui" "muo" "out" "ui" "uo")) + (t nil)) + "*Alist of Prolog mode specificators used by font locking." + :group 'prolog-font-lock + :type 'sexp) + +(defcustom prolog-determinism-specificators + '((mercury + ("cc_multi" "cc_nondet" "det" "erroneous" "failure" "multi" "nondet" + "semidet")) + (t nil)) + "*Alist of Prolog determinism specificators used by font locking." + :group 'prolog-font-lock + :type 'sexp) + +(defcustom prolog-directives + '((mercury + ("^#[0-9]+")) + (t nil)) + "*Alist of Prolog source code directives used by font locking." + :group 'prolog-font-lock + :type 'sexp) + + +;; Keyboard + +(defcustom prolog-electric-newline-flag t + "*Non-nil means automatically indent the next line when the user types RET." + :group 'prolog-keyboard + :type 'boolean) + +(defcustom prolog-hungry-delete-key-flag nil + "*Non-nil means delete key consumes all preceding spaces." + :group 'prolog-keyboard + :type 'boolean) + +(defcustom prolog-electric-dot-flag nil + "*Non-nil means make dot key electric. +Electric dot appends newline or inserts head of a new clause. +If dot is pressed at the end of a line where at least one white space +precedes the point, it inserts a recursive call to the current predicate. +If dot is pressed at the beginning of an empty line, it inserts the head +of a new clause for the current predicate. It does not apply in strings +and comments. +It does not apply in strings and comments." + :group 'prolog-keyboard + :type 'boolean) + +(defcustom prolog-electric-dot-full-predicate-template nil + "*If nil, electric dot inserts only the current predicate's name and `(' +for recursive calls or new clause heads. Non-nil means to also +insert enough commata to cover the predicate's arity and `)', +and dot and newline for recursive calls." + :group 'prolog-keyboard + :type 'boolean) + +(defcustom prolog-electric-underscore-flag nil + "*Non-nil means make underscore key electric. +Electric underscore replaces the current variable with underscore. +If underscore is pressed not on a variable then it behaves as usual." + :group 'prolog-keyboard + :type 'boolean) + +(defcustom prolog-electric-tab-flag nil + "*Non-nil means make TAB key electric. +Electric TAB inserts spaces after parentheses, ->, and ; +in ( If -> Then ; Else) and ( Disj1 ; Disj2 ) style expressions." + :group 'prolog-keyboard + :type 'boolean) + +(defcustom prolog-electric-if-then-else-flag nil + "*Non-nil makes `(', `>' and `;' electric +to automatically indent if-then-else constructs." + :group 'prolog-keyboard + :type 'boolean) + +(defcustom prolog-electric-colon-flag nil + "*Makes `:' electric (inserts `:-' on a new line). +If non-nil, pressing `:' at the end of a line that starts in +the first column (i.e., clause heads) inserts ` :-' and newline." + :group 'prolog-keyboard + :type 'boolean) + +(defcustom prolog-electric-dash-flag nil + "*Makes `-' electric (inserts a `-->' on a new line). +If non-nil, pressing `-' at the end of a line that starts in +the first column (i.e., DCG heads) inserts ` -->' and newline." + :group 'prolog-keyboard + :type 'boolean) + +(defcustom prolog-old-sicstus-keys-flag nil + "*Non-nil means old SICStus Prolog mode keybindings are used." + :group 'prolog-keyboard + :type 'boolean) + +;; Inferior mode + +(defcustom prolog-program-name + `(((getenv "EPROLOG") (eval (getenv "EPROLOG"))) + (eclipse "eclipse") + (mercury nil) + (sicstus "sicstus") + (swi ,(if (not (executable-find "swipl")) "pl" "swipl")) + (gnu "gprolog") + (xsb "xsb") + (t ,(let ((names '("prolog" "gprolog" "swipl" "pl"))) + (while (and names + (not (executable-find (car names)))) + (setq names (cdr names))) + (or (car names) "prolog")))) + "*Alist of program names for invoking an inferior Prolog with `run-prolog'." + :group 'prolog-inferior + :type 'sexp) + +(defcustom prolog-program-switches + '((sicstus ("-i")) + (t nil)) + "*Alist of switches given to inferior Prolog run with `run-prolog'." + :group 'prolog-inferior + :type 'sexp) + +(defcustom prolog-consult-string + '((eclipse "[%f].") + (mercury nil) + (sicstus (eval (if (prolog-atleast-version '(3 . 7)) + "prolog:zap_file(%m,%b,consult,%l)." + "prolog:zap_file(%m,%b,consult)."))) + (swi "[%f].") + (gnu "[%f].") + (xsb "[%f].") + (t "reconsult(%f).")) + "*Alist of strings defining predicate for reconsulting. + +Some parts of the string are replaced: +`%f' by the name of the consulted file (can be a temporary file) +`%b' by the file name of the buffer to consult +`%m' by the module name and name of the consulted file separated by colon +`%l' by the line offset into the file. This is 0 unless consulting a + region of a buffer, in which case it is the number of lines before + the region." + :group 'prolog-inferior + :type 'sexp) + +(defcustom prolog-compile-string + '((eclipse "[%f].") + (mercury "mmake ") + (sicstus (eval (if (prolog-atleast-version '(3 . 7)) + "prolog:zap_file(%m,%b,compile,%l)." + "prolog:zap_file(%m,%b,compile)."))) + (swi "[%f].") + (t "compile(%f).")) + "*Alist of strings and lists defining predicate for recompilation. + +Some parts of the string are replaced: +`%f' by the name of the compiled file (can be a temporary file) +`%b' by the file name of the buffer to compile +`%m' by the module name and name of the compiled file separated by colon +`%l' by the line offset into the file. This is 0 unless compiling a + region of a buffer, in which case it is the number of lines before + the region. + +If `prolog-program-name' is non-nil, it is a string sent to a Prolog process. +If `prolog-program-name' is nil, it is an argument to the `compile' function." + :group 'prolog-inferior + :type 'sexp) + +(defcustom prolog-eof-string "end_of_file.\n" + "*Alist of strings that represent end of file for prolog. +nil means send actual operating system end of file." + :group 'prolog-inferior + :type 'sexp) + +(defcustom prolog-prompt-regexp + '((eclipse "^[a-zA-Z0-9()]* *\\?- \\|^\\[[a-zA-Z]* [0-9]*\\]:") + (sicstus "| [ ?][- ] *") + (swi "^\\(\\[[a-zA-Z]*\\] \\)?[1-9]?[0-9]*[ ]?\\?- \\|^| +") + (t "^ *\\?-")) + "*Alist of prompts of the prolog system command line." + :group 'prolog-inferior + :type 'sexp) + +(defcustom prolog-continued-prompt-regexp + '((sicstus "^\\(| +\\| +\\)") + (t "^|: +")) + "*Alist of regexps matching the prompt when consulting `user'." + :group 'prolog-inferior + :type 'sexp) + +(defcustom prolog-debug-on-string "debug.\n" + "*Predicate for enabling debug mode." + :group 'prolog-inferior + :type 'string) + +(defcustom prolog-debug-off-string "nodebug.\n" + "*Predicate for disabling debug mode." + :group 'prolog-inferior + :type 'string) + +(defcustom prolog-trace-on-string "trace.\n" + "*Predicate for enabling tracing." + :group 'prolog-inferior + :type 'string) + +(defcustom prolog-trace-off-string "notrace.\n" + "*Predicate for disabling tracing." + :group 'prolog-inferior + :type 'string) + +(defcustom prolog-zip-on-string "zip.\n" + "*Predicate for enabling zip mode for SICStus." + :group 'prolog-inferior + :type 'string) + +(defcustom prolog-zip-off-string "nozip.\n" + "*Predicate for disabling zip mode for SICStus." + :group 'prolog-inferior + :type 'string) + +(defcustom prolog-use-standard-consult-compile-method-flag t + "*Non-nil means use the standard compilation method. +Otherwise the new compilation method will be used. This +utilises a special compilation buffer with the associated +features such as parsing of error messages and automatically +jumping to the source code responsible for the error. + +Warning: the new method is so far only experimental and +does contain bugs. The recommended setting for the novice user +is non-nil for this variable." + :group 'prolog-inferior + :type 'boolean) + + +;; Miscellaneous + +(defcustom prolog-use-prolog-tokenizer-flag t + "*Non-nil means use the internal prolog tokenizer for indentation etc. +Otherwise use `parse-partial-sexp' which is faster but sometimes incorrect." + :group 'prolog-other + :type 'boolean) + +(defcustom prolog-imenu-flag t + "*Non-nil means add a clause index menu for all prolog files." + :group 'prolog-other + :type 'boolean) + +(defcustom prolog-imenu-max-lines 3000 + "*The maximum number of lines of the file for imenu to be enabled. +Relevant only when `prolog-imenu-flag' is non-nil." + :group 'prolog-other + :type 'integer) + +(defcustom prolog-info-predicate-index + "(sicstus)Predicate Index" + "*The info node for the SICStus predicate index." + :group 'prolog-other + :type 'string) + +(defcustom prolog-underscore-wordchar-flag nil + "*Non-nil means underscore (_) is a word-constituent character." + :group 'prolog-other + :type 'boolean) + +(defcustom prolog-use-sicstus-sd nil + "*If non-nil, use the source level debugger of SICStus 3#7 and later." + :group 'prolog-other + :type 'boolean) + +(defcustom prolog-char-quote-workaround nil + "*If non-nil, declare 0 as a quote character so that 0' does not break syntax highlighting. +This is really kludgy but I have not found any better way of handling it." + :group 'prolog-other + :type 'boolean) + + +;;------------------------------------------------------------------- +;; Internal variables +;;------------------------------------------------------------------- + +(defvar prolog-emacs + (if (string-match "XEmacs\\|Lucid" emacs-version) + 'xemacs + 'gnuemacs) + "The variant of Emacs we're running. +Valid values are 'gnuemacs and 'xemacs.") + +(defvar prolog-known-systems '(eclipse mercury sicstus swi gnu xsb)) + +;(defvar prolog-temp-filename "") ; Later set by `prolog-temporary-file' + +(defvar prolog-mode-syntax-table nil) +(defvar prolog-mode-abbrev-table nil) +(defvar prolog-mode-map nil) +(defvar prolog-upper-case-string "" + "A string containing all upper case characters. +Set by prolog-build-case-strings.") +(defvar prolog-lower-case-string "" + "A string containing all lower case characters. +Set by prolog-build-case-strings.") + +(defvar prolog-atom-char-regexp "" + "Set by prolog-set-atom-regexps.") +;; "Regexp specifying characters which constitute atoms without quoting.") +(defvar prolog-atom-regexp "" + "Set by prolog-set-atom-regexps.") + +(defconst prolog-left-paren "[[({]" + "The characters used as left parentheses for the indentation code.") +(defconst prolog-right-paren "[])}]" + "The characters used as right parentheses for the indentation code.") + +(defconst prolog-quoted-atom-regexp + "\\(^\\|[^0-9]\\)\\('\\([^\n']\\|\\\\'\\)*'\\)" + "Regexp matching a quoted atom.") +(defconst prolog-string-regexp + "\\(\"\\([^\n\"]\\|\\\\\"\\)*\"\\)" + "Regexp matching a string.") +(defconst prolog-head-delimiter "\\(:-\\|\\+:\\|-:\\|\\+\\?\\|-\\?\\|-->\\)" + "A regexp for matching on the end delimiter of a head (e.g. \":-\").") + +(defvar prolog-compilation-buffer "*prolog-compilation*" + "Name of the output buffer for Prolog compilation/consulting.") + +(defvar prolog-temporary-file-name nil) +(defvar prolog-keywords-i nil) +(defvar prolog-types-i nil) +(defvar prolog-mode-specificators-i nil) +(defvar prolog-determinism-specificators-i nil) +(defvar prolog-directives-i nil) +(defvar prolog-program-name-i nil) +(defvar prolog-program-switches-i nil) +(defvar prolog-consult-string-i nil) +(defvar prolog-compile-string-i nil) +(defvar prolog-eof-string-i nil) +(defvar prolog-prompt-regexp-i nil) +(defvar prolog-continued-prompt-regexp-i nil) +(defvar prolog-help-function-i nil) + +(defvar prolog-align-rules + (eval-when-compile + (mapcar + (lambda (x) + (let ((name (car x)) + (sym (cdr x))) + `(,(intern (format "prolog-%s" name)) + (regexp . ,(format "\\(\\s-*\\)%s\\(\\s-*\\)" sym)) + (tab-stop . nil) + (modes . '(prolog-mode)) + (group . (1 2))))) + '(("dcg" . "-->") ("rule" . ":-") ("simplification" . "<=>") + ("propagation" . "==>"))))) + + + +;;------------------------------------------------------------------- +;; Prolog mode +;;------------------------------------------------------------------- + +;; Example: (prolog-atleast-version '(3 . 6)) +(defun prolog-atleast-version (version) + "Return t if the version of the current prolog system is VERSION or later. +VERSION is of the format (Major . Minor)" + ;; Version.major < major or + ;; Version.major = major and Version.minor <= minor + (let* ((thisversion (prolog-find-value-by-system prolog-system-version)) + (thismajor (car thisversion)) + (thisminor (cdr thisversion))) + (or (< (car version) thismajor) + (and (= (car version) thismajor) + (<= (cdr version) thisminor))) + )) + +(if prolog-mode-syntax-table + () + (let ((table (make-syntax-table))) + (if prolog-underscore-wordchar-flag + (modify-syntax-entry ?_ "w" table) + (modify-syntax-entry ?_ "_" table)) + + (modify-syntax-entry ?+ "." table) + (modify-syntax-entry ?- "." table) + (modify-syntax-entry ?= "." table) + (modify-syntax-entry ?< "." table) + (modify-syntax-entry ?> "." table) + (modify-syntax-entry ?| "." table) + (modify-syntax-entry ?\' "\"" table) + + ;; Any better way to handle the 0' construct?!? + (when prolog-char-quote-workaround + (modify-syntax-entry ?0 "\\" table)) + + (modify-syntax-entry ?% "<" table) + (modify-syntax-entry ?\n ">" table) + (if (eq prolog-emacs 'xemacs) + (progn + (modify-syntax-entry ?* ". 67" table) + (modify-syntax-entry ?/ ". 58" table) + ) + ;; Emacs wants to see this it seems: + (modify-syntax-entry ?* ". 23b" table) + (modify-syntax-entry ?/ ". 14" table) + ) + (setq prolog-mode-syntax-table table))) + +(define-abbrev-table 'prolog-mode-abbrev-table ()) + +(defun prolog-find-value-by-system (alist) + "Get value from ALIST according to `prolog-system'." + (if (listp alist) + (let (result + id) + (while alist + (setq id (car (car alist))) + (if (or (eq id prolog-system) + (eq id t) + (and (listp id) + (eval id))) + (progn + (setq result (car (cdr (car alist)))) + (if (and (listp result) + (eq (car result) 'eval)) + (setq result (eval (car (cdr result))))) + (setq alist nil)) + (setq alist (cdr alist)))) + result) + alist)) + +(defun prolog-mode-variables () + "Set some common variables to Prolog code specific values." + (setq local-abbrev-table prolog-mode-abbrev-table) + (make-local-variable 'paragraph-start) + (setq paragraph-start (concat "[ \t]*$\\|" page-delimiter)) ;'%%..' + (make-local-variable 'paragraph-separate) + (setq paragraph-separate paragraph-start) + (make-local-variable 'paragraph-ignore-fill-prefix) + (setq paragraph-ignore-fill-prefix t) + (make-local-variable 'adaptive-fill-mode) + (setq adaptive-fill-mode t) + (make-local-variable 'normal-auto-fill-function) + (setq normal-auto-fill-function 'prolog-do-auto-fill) + (make-local-variable 'indent-line-function) + (setq indent-line-function 'prolog-indent-line) + (make-local-variable 'comment-start) + (setq comment-start "%") + (make-local-variable 'comment-end) + (setq comment-end "") + (make-local-variable 'comment-start-skip) + ;; This complex regexp makes sure that comments cannot start + ;; inside quoted atoms or strings + (setq comment-start-skip + (format "^\\(\\(%s\\|%s\\|[^\n\'\"%%]\\)*\\)\\(/\\*+ *\\|%%+ *\\)" + prolog-quoted-atom-regexp prolog-string-regexp)) + (make-local-variable 'comment-column) + (make-local-variable 'comment-indent-function) + (setq comment-indent-function 'prolog-comment-indent) + (make-local-variable 'comment-indent-function) + (setq comment-indent-function 'prolog-comment-indent) + (make-local-variable 'parens-require-spaces) + (setq parens-require-spaces nil) + ;; Initialize Prolog system specific variables + (let ((vars '(prolog-keywords prolog-types prolog-mode-specificators + prolog-determinism-specificators prolog-directives + prolog-program-name prolog-program-switches + prolog-consult-string prolog-compile-string prolog-eof-string + prolog-prompt-regexp prolog-continued-prompt-regexp + prolog-help-function))) + (while vars + (set (intern (concat (symbol-name (car vars)) "-i")) + (prolog-find-value-by-system (eval (car vars)))) + (setq vars (cdr vars)))) + (when (null prolog-program-name-i) + (make-local-variable 'compile-command) + (setq compile-command prolog-compile-string-i)) + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults + '(prolog-font-lock-keywords nil nil ((?_ . "w")))) +) + +(defun prolog-mode-keybindings-common (map) + "Define keybindings common to both Prolog modes in MAP." + (define-key map "\C-c?" 'prolog-help-on-predicate) + (define-key map "\C-c/" 'prolog-help-apropos) + (define-key map "\C-c\C-d" 'prolog-debug-on) + (define-key map "\C-c\C-t" 'prolog-trace-on) + (if (and (eq prolog-system 'sicstus) + (prolog-atleast-version '(3 . 7))) + (define-key map "\C-c\C-z" 'prolog-zip-on)) + (define-key map "\C-c\r" 'run-prolog)) + +(defun prolog-mode-keybindings-edit (map) + "Define keybindings for Prolog mode in MAP." + (define-key map "\M-a" 'prolog-beginning-of-clause) + (define-key map "\M-e" 'prolog-end-of-clause) + (define-key map "\M-q" 'prolog-fill-paragraph) + (define-key map "\C-c\C-a" 'align) + (define-key map "\C-\M-a" 'prolog-beginning-of-predicate) + (define-key map "\C-\M-e" 'prolog-end-of-predicate) + (define-key map "\M-\C-c" 'prolog-mark-clause) + (define-key map "\M-\C-h" 'prolog-mark-predicate) + (define-key map "\M-\C-n" 'prolog-forward-list) + (define-key map "\M-\C-p" 'prolog-backward-list) + (define-key map "\C-c\C-n" 'prolog-insert-predicate-template) + (define-key map "\C-c\C-s" 'prolog-insert-predspec) + (define-key map "\M-\r" 'prolog-insert-next-clause) + (define-key map "\C-c\C-va" 'prolog-variables-to-anonymous) + (define-key map "\C-c\C-v\C-s" 'prolog-view-predspec) + + (define-key map [Backspace] 'prolog-electric-delete) + (define-key map "." 'prolog-electric-dot) + (define-key map "_" 'prolog-electric-underscore) + (define-key map "(" 'prolog-electric-if-then-else) + (define-key map ";" 'prolog-electric-if-then-else) + (define-key map ">" 'prolog-electric-if-then-else) + (define-key map ":" 'prolog-electric-colon) + (define-key map "-" 'prolog-electric-dash) + (if prolog-electric-newline-flag + (define-key map "\r" 'newline-and-indent)) + + ;; If we're running SICStus, then map C-c C-c e/d to enabling + ;; and disabling of the source-level debugging facilities. + ;(if (and (eq prolog-system 'sicstus) + ; (prolog-atleast-version '(3 . 7))) + ; (progn + ; (define-key map "\C-c\C-ce" 'prolog-enable-sicstus-sd) + ; (define-key map "\C-c\C-cd" 'prolog-disable-sicstus-sd) + ; )) + + (if prolog-old-sicstus-keys-flag + (progn + (define-key map "\C-c\C-c" 'prolog-consult-predicate) + (define-key map "\C-cc" 'prolog-consult-region) + (define-key map "\C-cC" 'prolog-consult-buffer) + (define-key map "\C-c\C-k" 'prolog-compile-predicate) + (define-key map "\C-ck" 'prolog-compile-region) + (define-key map "\C-cK" 'prolog-compile-buffer)) + (define-key map "\C-c\C-p" 'prolog-consult-predicate) + (define-key map "\C-c\C-r" 'prolog-consult-region) + (define-key map "\C-c\C-b" 'prolog-consult-buffer) + (define-key map "\C-c\C-f" 'prolog-consult-file) + (define-key map "\C-c\C-cp" 'prolog-compile-predicate) + (define-key map "\C-c\C-cr" 'prolog-compile-region) + (define-key map "\C-c\C-cb" 'prolog-compile-buffer) + (define-key map "\C-c\C-cf" 'prolog-compile-file))) + +(defun prolog-mode-keybindings-inferior (map) + "Define keybindings for inferior Prolog mode in MAP." + ;; No inferior mode specific keybindings now. + ) + +(if prolog-mode-map + () + (setq prolog-mode-map (make-sparse-keymap)) + (prolog-mode-keybindings-common prolog-mode-map) + (prolog-mode-keybindings-edit prolog-mode-map) + ;; System dependent keymaps for system dependent menus + (let ((systems prolog-known-systems)) + (while systems + (set (intern (concat "prolog-mode-map-" + (symbol-name (car systems)))) + ;(cons 'keymap prolog-mode-map) + prolog-mode-map + ) + (setq systems (cdr systems)))) + ) + + +(defvar prolog-mode-hook nil + "List of functions to call after the prolog mode has initialised.") + +;;;###autoload +(defun prolog-mode (&optional system) + "Major mode for editing Prolog code. + +Blank lines and `%%...' separate paragraphs. `%'s starts a comment +line and comments can also be enclosed in /* ... */. + +If an optional argument SYSTEM is non-nil, set up mode for the given system. + +To find out what version of Prolog mode you are running, enter +`\\[prolog-mode-version]'. + +Commands: +\\{prolog-mode-map} +Entry to this mode calls the value of `prolog-mode-hook' +if that value is non-nil." + (interactive) + (kill-all-local-variables) + (if system (setq prolog-system system)) + (use-local-map + (if prolog-system + ;; ### Looks like it works under XEmacs as well... + ;; (and prolog-system + ;; (not (eq prolog-emacs 'xemacs))) + (eval (intern (concat "prolog-mode-map-" (symbol-name prolog-system)))) + prolog-mode-map) + ) + (setq major-mode 'prolog-mode) + (setq mode-name (concat "Prolog" + (cond + ((eq prolog-system 'eclipse) "[ECLiPSe]") + ((eq prolog-system 'mercury) "[Mercury]") + ((eq prolog-system 'sicstus) "[SICStus]") + ((eq prolog-system 'swi) "[SWI]") + ((eq prolog-system 'gnu) "[GNU]") + ((eq prolog-system 'xsb) "[XSB]") + (t "")))) + (set-syntax-table prolog-mode-syntax-table) + (prolog-mode-variables) + (prolog-build-case-strings) + (prolog-set-atom-regexps) + (dolist (ar prolog-align-rules) (add-to-list 'align-rules-list ar)) + + ;; imenu entry moved to the appropriate hook for consistency + + ;; Load SICStus debugger if suitable + (if (and (eq prolog-system 'sicstus) + (prolog-atleast-version '(3 . 7)) + prolog-use-sicstus-sd) + (prolog-enable-sicstus-sd)) + + (run-mode-hooks 'prolog-mode-hook)) + +;;;###autoload +(defun mercury-mode () + "Major mode for editing Mercury programs. +Actually this is just customized `prolog-mode'." + (interactive) + (prolog-mode 'mercury)) + +;;;###autoload +(defun xsb-mode () + "Major mode for editing XSB programs. +Actually this is just customized `prolog-mode'." + (interactive) + (prolog-mode 'xsb)) + + +;;------------------------------------------------------------------- +;; Inferior prolog mode +;;------------------------------------------------------------------- + +(defvar prolog-inferior-mode-map nil) +(defvar prolog-inferior-mode-hook nil + "List of functions to call after the inferior prolog mode has initialised.") + +(defun prolog-inferior-mode () + "Major mode for interacting with an inferior Prolog process. + +The following commands are available: +\\{prolog-inferior-mode-map} + +Entry to this mode calls the value of `prolog-mode-hook' with no arguments, +if that value is non-nil. Likewise with the value of `comint-mode-hook'. +`prolog-mode-hook' is called after `comint-mode-hook'. + +You can send text to the inferior Prolog from other buffers +using the commands `send-region', `send-string' and \\[prolog-consult-region]. + +Commands: +Tab indents for Prolog; with argument, shifts rest + of expression rigidly with the current line. +Paragraphs are separated only by blank lines and '%%'. '%'s start comments. + +Return at end of buffer sends line as input. +Return not at end copies rest of line to end and sends it. +\\[comint-delchar-or-maybe-eof] sends end-of-file as input. +\\[comint-kill-input] and \\[backward-kill-word] are kill commands, +imitating normal Unix input editing. +\\[comint-interrupt-subjob] interrupts the shell or its current subjob if any. +\\[comint-stop-subjob] stops, likewise. +\\[comint-quit-subjob] sends quit signal, likewise. + +To find out what version of Prolog mode you are running, enter +`\\[prolog-mode-version]'." + (interactive) + (cond ((not (eq major-mode 'prolog-inferior-mode)) + (kill-all-local-variables) + (comint-mode) + (setq comint-input-filter 'prolog-input-filter) + (setq major-mode 'prolog-inferior-mode) + (setq mode-name "Inferior Prolog") + (setq mode-line-process '(": %s")) + (prolog-mode-variables) + (if prolog-inferior-mode-map + () + (setq prolog-inferior-mode-map (copy-keymap comint-mode-map)) + (prolog-mode-keybindings-common prolog-inferior-mode-map) + (prolog-mode-keybindings-inferior prolog-inferior-mode-map)) + (use-local-map prolog-inferior-mode-map) + (setq comint-prompt-regexp prolog-prompt-regexp-i) + ;(make-variable-buffer-local 'shell-dirstack-query) + (make-local-variable 'shell-dirstack-query) + (setq shell-dirstack-query "pwd.") + (run-hooks 'prolog-inferior-mode-hook)))) + +(defun prolog-input-filter (str) + (cond ((string-match "\\`\\s *\\'" str) nil) ;whitespace + ((not (eq major-mode 'prolog-inferior-mode)) t) + ((= (length str) 1) nil) ;one character + ((string-match "\\`[rf] *[0-9]*\\'" str) nil) ;r(edo) or f(ail) + (t t))) + +;;;###autoload +(defun run-prolog (arg) + "Run an inferior Prolog process, input and output via buffer *prolog*. +With prefix argument ARG, restart the Prolog process if running before." + (interactive "P") + (if (and arg (get-process "prolog")) + (progn + (process-send-string "prolog" "halt.\n") + (while (get-process "prolog") (sit-for 0.1)))) + (let ((buff (buffer-name))) + (if (not (string= buff "*prolog*")) + (prolog-goto-prolog-process-buffer)) + ;; Load SICStus debugger if suitable + (if (and (eq prolog-system 'sicstus) + (prolog-atleast-version '(3 . 7)) + prolog-use-sicstus-sd) + (prolog-enable-sicstus-sd)) + (prolog-mode-variables) + (prolog-ensure-process) + )) + +(defun prolog-ensure-process (&optional wait) + "If Prolog process is not running, run it. +If the optional argument WAIT is non-nil, wait for Prolog prompt specified by +the variable `prolog-prompt-regexp'." + (if (null prolog-program-name-i) + (error "This Prolog system has defined no interpreter.")) + (if (comint-check-proc "*prolog*") + () + (apply 'make-comint "prolog" prolog-program-name-i nil + prolog-program-switches-i) + (save-excursion + (set-buffer "*prolog*") + (prolog-inferior-mode) + (if wait + (progn + (goto-char (point-max)) + (while + (save-excursion + (not + (re-search-backward + (concat "\\(" prolog-prompt-regexp-i "\\)" "\\=") + nil t))) + (sit-for 0.1))))))) + +(defun prolog-process-insert-string (process string) + "Insert STRING into inferior Prolog buffer running PROCESS." + ;; Copied from elisp manual, greek to me + (let ((buf (current-buffer))) + (unwind-protect + (let (moving) + (set-buffer (process-buffer process)) + (setq moving (= (point) (process-mark process))) + (save-excursion + ;; Insert the text, moving the process-marker. + (goto-char (process-mark process)) + (insert string) + (set-marker (process-mark process) (point))) + (if moving (goto-char (process-mark process)))) + (set-buffer buf)))) + + +;;------------------------------------------------------------ +;; Old consulting and compiling functions +;;------------------------------------------------------------ + +(defun prolog-old-process-region (compilep start end) + "Process the region limited by START and END positions. +If COMPILEP is non-nil then use compilation, otherwise consulting." + (prolog-ensure-process) + ;(let ((tmpfile prolog-temp-filename) + (let ((tmpfile (prolog-bsts (prolog-temporary-file))) + ;(process (get-process "prolog")) + (first-line (1+ (count-lines + (point-min) + (save-excursion + (goto-char start) + (point)))))) + (write-region start end tmpfile) + (process-send-string + "prolog" (prolog-build-prolog-command + compilep tmpfile (prolog-bsts buffer-file-name) + first-line)) + (prolog-goto-prolog-process-buffer))) + +(defun prolog-old-process-predicate (compilep) + "Process the predicate around point. +If COMPILEP is non-nil then use compilation, otherwise consulting." + (prolog-old-process-region + compilep (prolog-pred-start) (prolog-pred-end))) + +(defun prolog-old-process-buffer (compilep) + "Process the entire buffer. +If COMPILEP is non-nil then use compilation, otherwise consulting." + (prolog-old-process-region compilep (point-min) (point-max))) + +(defun prolog-old-process-file (compilep) + "Process the file of the current buffer. +If COMPILEP is non-nil then use compilation, otherwise consulting." + (save-some-buffers) + (prolog-ensure-process) + (let ((filename (prolog-bsts buffer-file-name))) + (process-send-string + "prolog" (prolog-build-prolog-command + compilep filename filename)) + (prolog-goto-prolog-process-buffer))) + + +;;------------------------------------------------------------ +;; Consulting and compiling +;;------------------------------------------------------------ + +;;; Interactive interface functions, used by both the standard +;;; and the experimental consultation and compilation functions +(defun prolog-consult-file () + "Consult file of current buffer." + (interactive) + (if prolog-use-standard-consult-compile-method-flag + (prolog-old-process-file nil) + (prolog-consult-compile-file nil))) + +(defun prolog-consult-buffer () + "Consult buffer." + (interactive) + (if prolog-use-standard-consult-compile-method-flag + (prolog-old-process-buffer nil) + (prolog-consult-compile-buffer nil))) + +(defun prolog-consult-region (beg end) + "Consult region between BEG and END." + (interactive "r") + (if prolog-use-standard-consult-compile-method-flag + (prolog-old-process-region nil beg end) + (prolog-consult-compile-region nil beg end))) + +(defun prolog-consult-predicate () + "Consult the predicate around current point." + (interactive) + (if prolog-use-standard-consult-compile-method-flag + (prolog-old-process-predicate nil) + (prolog-consult-compile-predicate nil))) + +(defun prolog-compile-file () + "Compile file of current buffer." + (interactive) + (if prolog-use-standard-consult-compile-method-flag + (prolog-old-process-file t) + (prolog-consult-compile-file t))) + +(defun prolog-compile-buffer () + "Compile buffer." + (interactive) + (if prolog-use-standard-consult-compile-method-flag + (prolog-old-process-buffer t) + (prolog-consult-compile-buffer t))) + +(defun prolog-compile-region (beg end) + "Compile region between BEG and END." + (interactive "r") + (if prolog-use-standard-consult-compile-method-flag + (prolog-old-process-region t beg end) + (prolog-consult-compile-region t beg end))) + +(defun prolog-compile-predicate () + "Compile the predicate around current point." + (interactive) + (if prolog-use-standard-consult-compile-method-flag + (prolog-old-process-predicate t) + (prolog-consult-compile-predicate t))) + +(defun prolog-buffer-module () + "Select Prolog module name appropriate for current buffer. +Bases decision on buffer contents (-*- line)." + ;; Look for -*- ... module: MODULENAME; ... -*- + (let (beg end) + (save-excursion + (goto-char (point-min)) + (skip-chars-forward " \t") + (and (search-forward "-*-" (save-excursion (end-of-line) (point)) t) + (progn + (skip-chars-forward " \t") + (setq beg (point)) + (search-forward "-*-" (save-excursion (end-of-line) (point)) t)) + (progn + (forward-char -3) + (skip-chars-backward " \t") + (setq end (point)) + (goto-char beg) + (and (let ((case-fold-search t)) + (search-forward "module:" end t)) + (progn + (skip-chars-forward " \t") + (setq beg (point)) + (if (search-forward ";" end t) + (forward-char -1) + (goto-char end)) + (skip-chars-backward " \t") + (buffer-substring beg (point))))))))) + +(defun prolog-build-prolog-command (compilep file buffername + &optional first-line) + "Make Prolog command for FILE compilation/consulting. +If COMPILEP is non-nil, consider compilation, otherwise consulting." + (let* ((compile-string + (if compilep prolog-compile-string-i prolog-consult-string-i)) + (module (prolog-buffer-module)) + (file-name (concat "'" file "'")) + (module-name (if module (concat "'" module "'"))) + (module-file (if module + (concat module-name ":" file-name) + file-name)) + strbeg strend + (lineoffset (if first-line + (- first-line 1) + 0))) + + ;; Assure that there is a buffer name + (if (not buffername) + (error "The buffer is not saved")) + + (if (not (string-match "^'.*'$" buffername)) ; Add quotes + (setq buffername (concat "'" buffername "'"))) + (while (string-match "%m" compile-string) + (setq strbeg (substring compile-string 0 (match-beginning 0))) + (setq strend (substring compile-string (match-end 0))) + (setq compile-string (concat strbeg module-file strend))) + (while (string-match "%f" compile-string) + (setq strbeg (substring compile-string 0 (match-beginning 0))) + (setq strend (substring compile-string (match-end 0))) + (setq compile-string (concat strbeg file-name strend))) + (while (string-match "%b" compile-string) + (setq strbeg (substring compile-string 0 (match-beginning 0))) + (setq strend (substring compile-string (match-end 0))) + (setq compile-string (concat strbeg buffername strend))) + (while (string-match "%l" compile-string) + (setq strbeg (substring compile-string 0 (match-beginning 0))) + (setq strend (substring compile-string (match-end 0))) + (setq compile-string (concat strbeg (format "%d" lineoffset) strend))) + (concat compile-string "\n"))) + +;;; The rest of this page is experimental code! + +;; Global variables for process filter function +(defvar prolog-process-flag nil + "Non-nil means that a prolog task (i.e. a consultation or compilation job) +is running.") +(defvar prolog-consult-compile-output "" + "Hold the unprocessed output from the current prolog task.") +(defvar prolog-consult-compile-first-line 1 + "The number of the first line of the file to consult/compile. +Used for temporary files.") +(defvar prolog-consult-compile-file nil + "The file to compile/consult (can be a temporary file).") +(defvar prolog-consult-compile-real-file nil + "The file name of the buffer to compile/consult.") + +(defun prolog-consult-compile (compilep file &optional first-line) + "Consult/compile FILE. +If COMPILEP is non-nil, perform compilation, otherwise perform CONSULTING. +COMMAND is a string described by the variables `prolog-consult-string' +and `prolog-compile-string'. +Optional argument FIRST-LINE is the number of the first line in the compiled +region. + +This function must be called from the source code buffer." + (if prolog-process-flag + (error "Another Prolog task is running.")) + (prolog-ensure-process t) + (let* ((buffer (get-buffer-create prolog-compilation-buffer)) + (real-file buffer-file-name) + (command-string (prolog-build-prolog-command compilep file + real-file first-line)) + (process (get-process "prolog")) + (old-filter (process-filter process))) + (save-excursion + (set-buffer buffer) + (delete-region (point-min) (point-max)) + (compilation-mode) + ;; Setting up font-locking for this buffer + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults + '(prolog-font-lock-keywords nil nil ((?_ . "w")))) + (if (eq prolog-system 'sicstus) + (progn + (make-local-variable 'compilation-parse-errors-function) + (setq compilation-parse-errors-function + 'prolog-parse-sicstus-compilation-errors))) + (toggle-read-only 0) + (insert command-string "\n")) + (save-selected-window + (pop-to-buffer buffer)) + (setq prolog-process-flag t + prolog-consult-compile-output "" + prolog-consult-compile-first-line (if first-line (1- first-line) 0) + prolog-consult-compile-file file + prolog-consult-compile-real-file (if (string= + file buffer-file-name) + nil + real-file)) + (save-excursion + (set-buffer buffer) + (goto-char (point-max)) + (set-process-filter process 'prolog-consult-compile-filter) + (process-send-string "prolog" command-string) + ;; (prolog-build-prolog-command compilep file real-file first-line)) + (while (and prolog-process-flag + (accept-process-output process 10)) ; 10 secs is ok? + (sit-for 0.1) + (unless (get-process "prolog") + (setq prolog-process-flag nil))) + (insert (if compilep + "\nCompilation finished.\n" + "\nConsulted.\n")) + (set-process-filter process old-filter)))) + +(defun prolog-parse-sicstus-compilation-errors (limit) + "Parse the prolog compilation buffer for errors. +Argument LIMIT is a buffer position limiting searching. +For use with the `compilation-parse-errors-function' variable." + (setq compilation-error-list nil) + (message "Parsing SICStus error messages...") + (let (filepath dir file errorline) + (while + (re-search-backward + "{\\([a-zA-Z ]* ERROR\\|Warning\\):.* in line[s ]*\\([0-9]+\\)" + limit t) + (setq errorline (string-to-number (match-string 2))) + (save-excursion + (re-search-backward + "{\\(consulting\\|compiling\\|processing\\) \\(.*\\)\\.\\.\\.}" + limit t) + (setq filepath (match-string 2))) + + ;; ###### Does this work with SICStus under Windows (i.e. backslahes and stuff?) + (if (string-match "\\(.*/\\)\\([^/]*\\)$" filepath) + (progn + (setq dir (match-string 1 filepath)) + (setq file (match-string 2 filepath)))) + + (setq compilation-error-list + (cons + (cons (save-excursion + (beginning-of-line) + (point-marker)) + (list (list file dir) errorline)) + compilation-error-list) + )) + )) + +(defun prolog-consult-compile-filter (process output) + "Filter function for Prolog compilation PROCESS. +Argument OUTPUT is a name of the output file." + ;;(message "start") + (setq prolog-consult-compile-output + (concat prolog-consult-compile-output output)) + ;;(message "pccf1: %s" prolog-consult-compile-output) + ;; Iterate through the lines of prolog-consult-compile-output + (let (outputtype) + (while (and prolog-process-flag + (or + ;; Trace question + (progn + (setq outputtype 'trace) + (and (eq prolog-system 'sicstus) + (string-match + "^[ \t]*[0-9]+[ \t]*[0-9]+[ \t]*Call:.*? " + prolog-consult-compile-output))) + + ;; Match anything + (progn + (setq outputtype 'normal) + (string-match "^.*\n" prolog-consult-compile-output)) + )) + ;;(message "outputtype: %s" outputtype) + + (setq output (match-string 0 prolog-consult-compile-output)) + ;; remove the text in output from prolog-consult-compile-output + (setq prolog-consult-compile-output + (substring prolog-consult-compile-output (length output))) + ;;(message "pccf2: %s" prolog-consult-compile-output) + + ;; If temporary files were used, then we change the error + ;; messages to point to the original source file. + (cond + + ;; If the prolog process was in trace mode then it requires + ;; user input + ((and (eq prolog-system 'sicstus) + (eq outputtype 'trace)) + (let (input) + (setq input (concat (read-string output) "\n")) + (process-send-string "prolog" input) + (setq output (concat output input)))) + + ((eq prolog-system 'sicstus) + (if (and prolog-consult-compile-real-file + (string-match + "\\({.*:.* in line[s ]*\\)\\([0-9]+\\)-\\([0-9]+\\)" output)) + (setq output (replace-match + ;; Adds a {processing ...} line so that + ;; `prolog-parse-sicstus-compilation-errors' + ;; finds the real file instead of the temporary one. + ;; Also fixes the line numbers. + (format "Added by Emacs: {processing %s...}\n%s%d-%d" + prolog-consult-compile-real-file + (match-string 1 output) + (+ prolog-consult-compile-first-line + (string-to-number + (match-string 2 output))) + (+ prolog-consult-compile-first-line + (string-to-number + (match-string 3 output)))) + t t output))) + ) + + ((eq prolog-system 'swi) + (if (and prolog-consult-compile-real-file + (string-match (format + "%s\\([ \t]*:[ \t]*\\)\\([0-9]+\\)" + prolog-consult-compile-file) + output)) + (setq output (replace-match + ;; Real filename + text + fixed linenum + (format "%s%s%d" + prolog-consult-compile-real-file + (match-string 1 output) + (+ prolog-consult-compile-first-line + (string-to-number + (match-string 2 output)))) + t t output))) + ) + + (t ()) + ) + ;; Write the output in the *prolog-compilation* buffer + (insert output))) + + ;; If the prompt is visible, then the task is finished + (if (string-match prolog-prompt-regexp-i prolog-consult-compile-output) + (setq prolog-process-flag nil))) + +(defun prolog-consult-compile-file (compilep) + "Consult/compile file of current buffer. +If COMPILEP is non-nil, compile, otherwise consult." + (let ((file buffer-file-name)) + (if file + (progn + (save-some-buffers) + (prolog-consult-compile compilep file)) + (prolog-consult-compile-region compilep (point-min) (point-max))))) + +(defun prolog-consult-compile-buffer (compilep) + "Consult/compile current buffer. +If COMPILEP is non-nil, compile, otherwise consult." + (prolog-consult-compile-region compilep (point-min) (point-max))) + +(defun prolog-consult-compile-region (compilep beg end) + "Consult/compile region between BEG and END. +If COMPILEP is non-nil, compile, otherwise consult." + ;(let ((file prolog-temp-filename) + (let ((file (prolog-bsts (prolog-temporary-file))) + (lines (count-lines 1 beg))) + (write-region beg end file nil 'no-message) + (write-region "\n" nil file t 'no-message) + (prolog-consult-compile compilep file + (if (looking-at "^") (1+ lines) lines)) + (delete-file file))) + +(defun prolog-consult-compile-predicate (compilep) + "Consult/compile the predicate around current point. +If COMPILEP is non-nil, compile, otherwise consult." + (prolog-consult-compile-region + compilep (prolog-pred-start) (prolog-pred-end))) + + +;;------------------------------------------------------------------- +;; Font-lock stuff +;;------------------------------------------------------------------- + +;; Auxilliary functions +(defun prolog-make-keywords-regexp (keywords &optional protect) + "Create regexp from the list of strings KEYWORDS. +If PROTECT is non-nil, surround the result regexp by word breaks." + (let ((regexp + (if (fboundp 'regexp-opt) + ;; Emacs 20 + ;; Avoid compile warnings under earlier versions by using eval + (eval '(regexp-opt keywords)) + ;; Older Emacsen + (concat (mapconcat 'regexp-quote keywords "\\|"))) + )) + (if protect + (concat "\\<\\(" regexp "\\)\\>") + regexp))) + +(defun prolog-font-lock-object-matcher (bound) + "Find SICStus objects method name for font lock. +Argument BOUND is a buffer position limiting searching." + (let (point + (case-fold-search nil)) + (while (and (not point) + (re-search-forward "\\(::[ \t\n]*{\\|&\\)[ \t]*" + bound t)) + (while (or (re-search-forward "\\=\n[ \t]*" bound t) + (re-search-forward "\\=%.*" bound t) + (and (re-search-forward "\\=/\\*" bound t) + (re-search-forward "\\*/[ \t]*" bound t)))) + (setq point (re-search-forward + (format "\\=\\(%s\\)" prolog-atom-regexp) + bound t))) + point)) + +(defsubst prolog-face-name-p (facename) + ;; Return t if FACENAME is the name of a face. This method is + ;; necessary since facep in XEmacs only returns t for the actual + ;; face objects (while it's only their names that are used just + ;; about anywhere else) without providing a predicate that tests + ;; face names. This function (including the above commentary) is + ;; borrowed from cc-mode. + (memq facename (face-list))) + +;; Set everything up +(defun prolog-font-lock-keywords () + "Set up font lock keywords for the current Prolog system." + ;(when window-system + (require 'font-lock) + + ;; Define Prolog faces + (defface prolog-redo-face + '((((class grayscale)) (:italic t)) + (((class color)) (:foreground "darkorchid")) + (t (:italic t))) + "Prolog mode face for highlighting redo trace lines." + :group 'prolog-faces) + (defface prolog-exit-face + '((((class grayscale)) (:underline t)) + (((class color) (background dark)) (:foreground "green")) + (((class color) (background light)) (:foreground "ForestGreen")) + (t (:underline t))) + "Prolog mode face for highlighting exit trace lines." + :group 'prolog-faces) + (defface prolog-exception-face + '((((class grayscale)) (:bold t :italic t :underline t)) + (((class color)) (:bold t :foreground "black" :background "Khaki")) + (t (:bold t :italic t :underline t))) + "Prolog mode face for highlighting exception trace lines." + :group 'prolog-faces) + (defface prolog-warning-face + '((((class grayscale)) (:underline t)) + (((class color) (background dark)) (:foreground "blue")) + (((class color) (background light)) (:foreground "MidnightBlue")) + (t (:underline t))) + "Face name to use for compiler warnings." + :group 'prolog-faces) + (defface prolog-builtin-face + '((((class color) (background light)) (:foreground "Purple")) + (((class color) (background dark)) (:foreground "Cyan")) + (((class grayscale) (background light)) (:foreground "LightGray" :bold t)) + (((class grayscale) (background dark)) (:foreground "DimGray" :bold t)) + (t (:bold t))) + "Face name to use for compiler warnings." + :group 'prolog-faces) + (defvar prolog-warning-face + (if (prolog-face-name-p 'font-lock-warning-face) + 'font-lock-warning-face + 'prolog-warning-face) + "Face name to use for built in predicates.") + (defvar prolog-builtin-face + (if (prolog-face-name-p 'font-lock-builtin-face) + 'font-lock-builtin-face + 'prolog-builtin-face) + "Face name to use for built in predicates.") + (defvar prolog-redo-face 'prolog-redo-face + "Face name to use for redo trace lines.") + (defvar prolog-exit-face 'prolog-exit-face + "Face name to use for exit trace lines.") + (defvar prolog-exception-face 'prolog-exception-face + "Face name to use for exception trace lines.") + + ;; Font Lock Patterns + (let ( + ;; "Native" Prolog patterns + (head-predicates + (list (format "^\\(%s\\)\\((\\|[ \t]*:-\\)" prolog-atom-regexp) + 1 font-lock-function-name-face)) + ;(list (format "^%s" prolog-atom-regexp) + ; 0 font-lock-function-name-face)) + (head-predicates-1 + (list (format "\\.[ \t]*\\(%s\\)" prolog-atom-regexp) + 1 font-lock-function-name-face) ) + (variables + '("\\<\\([_A-Z][a-zA-Z0-9_]*\\)" + 1 font-lock-variable-name-face)) + (important-elements + (list (if (eq prolog-system 'mercury) + "[][}{;|]\\|\\\\[+=]\\|?" + "[][}{!;|]\\|\\*->") + 0 'font-lock-keyword-face)) + (important-elements-1 + '("[^-*]\\(->\\)" 1 font-lock-keyword-face)) + (predspecs ; module:predicate/cardinality + (list (format "\\<\\(%s:\\|\\)%s/[0-9]+" + prolog-atom-regexp prolog-atom-regexp) + 0 font-lock-function-name-face 'prepend)) + (keywords ; directives (queries) + (list + (if (eq prolog-system 'mercury) + (concat + "\\<\\(" + (prolog-make-keywords-regexp prolog-keywords-i) + "\\|" + (prolog-make-keywords-regexp + prolog-determinism-specificators-i) + "\\)\\>") + (concat + "^[?:]- *\\(" + (prolog-make-keywords-regexp prolog-keywords-i) + "\\)\\>")) + 1 prolog-builtin-face)) + (quoted_atom (list prolog-quoted-atom-regexp + 2 'font-lock-string-face 'append)) + (string (list prolog-string-regexp + 1 'font-lock-string-face 'append)) + ;; SICStus specific patterns + (sicstus-object-methods + (if (eq prolog-system 'sicstus) + '(prolog-font-lock-object-matcher + 1 font-lock-function-name-face))) + ;; Mercury specific patterns + (types + (if (eq prolog-system 'mercury) + (list + (prolog-make-keywords-regexp prolog-types-i t) + 0 'font-lock-type-face))) + (modes + (if (eq prolog-system 'mercury) + (list + (prolog-make-keywords-regexp prolog-mode-specificators-i t) + 0 'font-lock-reference-face))) + (directives + (if (eq prolog-system 'mercury) + (list + (prolog-make-keywords-regexp prolog-directives-i t) + 0 'prolog-warning-face))) + ;; Inferior mode specific patterns + (prompt + (list prolog-prompt-regexp-i 0 'font-lock-keyword-face)) + (trace-exit + (cond + ((eq prolog-system 'sicstus) + '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Exit\\):" + 1 prolog-exit-face)) + ((eq prolog-system 'swi) + '("[ \t]*\\(Exit\\):[ \t]*([ \t0-9]*)" 1 prolog-exit-face)) + (t nil))) + (trace-fail + (cond + ((eq prolog-system 'sicstus) + '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Fail\\):" + 1 prolog-warning-face)) + ((eq prolog-system 'swi) + '("[ \t]*\\(Fail\\):[ \t]*([ \t0-9]*)" 1 prolog-warning-face)) + (t nil))) + (trace-redo + (cond + ((eq prolog-system 'sicstus) + '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Redo\\):" + 1 prolog-redo-face)) + ((eq prolog-system 'swi) + '("[ \t]*\\(Redo\\):[ \t]*([ \t0-9]*)" 1 prolog-redo-face)) + (t nil))) + (trace-call + (cond + ((eq prolog-system 'sicstus) + '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Call\\):" + 1 font-lock-function-name-face)) + ((eq prolog-system 'swi) + '("[ \t]*\\(Call\\):[ \t]*([ \t0-9]*)" + 1 font-lock-function-name-face)) + (t nil))) + (trace-exception + (cond + ((eq prolog-system 'sicstus) + '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Exception\\):" + 1 prolog-exception-face)) + ((eq prolog-system 'swi) + '("[ \t]*\\(Exception\\):[ \t]*([ \t0-9]*)" + 1 prolog-exception-face)) + (t nil))) + (error-message-identifier + (cond + ((eq prolog-system 'sicstus) + '("{\\([A-Z]* ?ERROR:\\)" 1 prolog-exception-face prepend)) + ((eq prolog-system 'swi) + '("^[[]\\(WARNING:\\)" 1 prolog-builtin-face prepend)) + (t nil))) + (error-whole-messages + (cond + ((eq prolog-system 'sicstus) + '("{\\([A-Z]* ?ERROR:.*\\)}[ \t]*$" + 1 font-lock-comment-face append)) + ((eq prolog-system 'swi) + '("^[[]WARNING:[^]]*[]]$" 0 font-lock-comment-face append)) + (t nil))) + (error-warning-messages + ;; Mostly errors that SICStus asks the user about how to solve, + ;; such as "NAME CLASH:" for example. + (cond + ((eq prolog-system 'sicstus) + '("^[A-Z ]*[A-Z]+:" 0 prolog-warning-face)) + (t nil))) + (warning-messages + (cond + ((eq prolog-system 'sicstus) + '("\\({ ?\\(Warning\\|WARNING\\) ?:.*}\\)[ \t]*$" + 2 prolog-warning-face prepend)) + (t nil)))) + + ;; Make font lock list + (delq + nil + (cond + ((eq major-mode 'prolog-mode) + (list + head-predicates + head-predicates-1 + quoted_atom + string + variables + important-elements + important-elements-1 + predspecs + keywords + sicstus-object-methods + types + modes + directives)) + ((eq major-mode 'prolog-inferior-mode) + (list + prompt + error-message-identifier + error-whole-messages + error-warning-messages + warning-messages + predspecs + trace-exit + trace-fail + trace-redo + trace-call + trace-exception)) + ((eq major-mode 'compilation-mode) + (list + error-message-identifier + error-whole-messages + error-warning-messages + warning-messages + predspecs)))) + )) + + +;;------------------------------------------------------------------- +;; Indentation stuff +;;------------------------------------------------------------------- + +;; NB: This function *MUST* have this optional argument since XEmacs +;; assumes it. This does not mean we have to use it... +(defun prolog-indent-line (&optional whole-exp) + "Indent current line as Prolog code. +With argument, indent any additional lines of the same clause +rigidly along with this one (not yet)." + (interactive "p") + (let ((indent (prolog-indent-level)) + (pos (- (point-max) (point))) beg) + (beginning-of-line) + (setq beg (point)) + (skip-chars-forward " \t") + (if (zerop (- indent (current-column))) + nil + (delete-region beg (point)) + (indent-to indent)) + (if (> (- (point-max) pos) (point)) + (goto-char (- (point-max) pos))) + + ;; Align comments + (if prolog-align-comments-flag + (save-excursion + (prolog-goto-comment-column t))) + + ;; Insert spaces if needed + (if (or prolog-electric-tab-flag prolog-electric-if-then-else-flag) + (prolog-insert-spaces-after-paren)) + )) + +(defun prolog-comment-indent () + "Compute prolog comment indentation." + (cond ((looking-at "%%%") (prolog-indentation-level-of-line)) + ((looking-at "%%") (prolog-indent-level)) + (t + (save-excursion + (skip-chars-backward " \t") + ;; Insert one space at least, except at left margin. + (max (+ (current-column) (if (bolp) 0 1)) + comment-column))) + )) + +(defun prolog-indent-level () + "Compute prolog indentation level." + (save-excursion + (beginning-of-line) + (let ((totbal (prolog-region-paren-balance + (prolog-clause-start t) (point))) + (oldpoint (point))) + (skip-chars-forward " \t") + (cond + ((looking-at "%%%") (prolog-indentation-level-of-line)) + ;Large comment starts + ((looking-at "%[^%]") comment-column) ;Small comment starts + ((bobp) 0) ;Beginning of buffer + + ;; If we found '}' then we must check if it's the + ;; end of an object declaration or something else. + ((and (looking-at "}") + (save-excursion + (forward-char 1) + ;; Goto to matching { + (if prolog-use-prolog-tokenizer-flag + (prolog-backward-list) + (backward-list)) + (skip-chars-backward " \t") + (backward-char 2) + (looking-at "::"))) + ;; It was an object + (if prolog-object-end-to-0-flag + 0 + prolog-indent-width)) + + ;;End of /* */ comment + ((looking-at "\\*/") + (save-excursion + (prolog-find-start-of-mline-comment) + (skip-chars-backward " \t") + (- (current-column) 2))) + + ;; Here we check if the current line is within a /* */ pair + ((and (looking-at "[^%/]") + (eq (prolog-in-string-or-comment) 'cmt)) + (if prolog-indent-mline-comments-flag + (prolog-find-start-of-mline-comment) + ;; Same as before + (prolog-indentation-level-of-line))) + + (t + (let ((empty t) ind linebal) + ;; See previous indentation + (while empty + (forward-line -1) + (beginning-of-line) + (if (= (point) (point-min)) + (setq empty nil) + (skip-chars-forward " \t") + (if (not (or (not (member (prolog-in-string-or-comment) '(nil txt))) + (looking-at "%") + (looking-at "\n"))) + (setq empty nil)))) + + ;; Store this line's indentation + (if (= (point) (point-min)) + (setq ind 0) ;Beginning of buffer + (setq ind (current-column))) ;Beginning of clause + + ;; Compute the balance of the line + (setq linebal (prolog-paren-balance)) + ;;(message "bal of previous line %d totbal %d" linebal totbal) + (if (< linebal 0) + (progn + ;; Add 'indent-level' mode to find-unmatched-paren instead? + (end-of-line) + (setq ind (prolog-find-indent-of-matching-paren)))) + + ;;(message "ind %d" ind) + (beginning-of-line) + + ;; Check if the line ends with ":-", ".", ":: {", "}" (might be + ;; unnecessary), "&" or ")" (The last four concerns SICStus objects) + (cond + ;; If the last char of the line is a '&' then set the indent level + ;; to prolog-indent-width (used in SICStus objects) + ((and (eq prolog-system 'sicstus) + (looking-at ".+&[ \t]*\\(%.*\\|\\)$")) + (setq ind prolog-indent-width)) + + ;; Increase indentation if the previous line was the head of a rule + ;; and does not contain a '.' + ((and (looking-at (format ".*%s[^\\.]*[ \t]*\\(%%.*\\|\\)$" + prolog-head-delimiter)) + ;; We must check that the match is at a paren balance of 0. + (save-excursion + (let ((p (point))) + (re-search-forward prolog-head-delimiter) + (>= 0 (prolog-region-paren-balance p (point)))))) + (let (headindent) + (if (< (prolog-paren-balance) 0) + (save-excursion + (end-of-line) + (setq headindent (prolog-find-indent-of-matching-paren))) + (setq headindent (prolog-indentation-level-of-line))) + (setq ind (+ headindent prolog-indent-width)))) + + ;; The previous line was the head of an object + ((looking-at ".+ *::.*{[ \t]*$") + (setq ind prolog-indent-width)) + + ;; If a '.' is found at the end of the previous line, then + ;; decrease the indentation. (The \\(%.*\\|\\) part of the + ;; regexp is for comments at the end of the line) + ((and (looking-at "^.+\\.[ \t]*\\(%.*\\|\\)$") + ;; Make sure that the '.' found is not in a comment or string + (save-excursion + (end-of-line) + (re-search-backward "\\.[ \t]*\\(%.*\\|\\)$" (point-min)) + ;; Guard against the real '.' being followed by a + ;; commented '.'. + (if (eq (prolog-in-string-or-comment) 'cmt) ;; commented out '.' + (let ((here (save-excursion + (beginning-of-line) + (point)))) + (end-of-line) + (re-search-backward "\\.[ \t]*%.*$" here t)) + (not (prolog-in-string-or-comment)) + ) + )) + (setq ind 0)) + + ;; If a '.' is found at the end of the previous line, then + ;; decrease the indentation. (The /\\*.*\\*/ part of the + ;; regexp is for C-like comments at the end of the + ;; line--can we merge with the case above?). + ((and (looking-at "^.+\\.[ \t]*\\(/\\*.*\\|\\)$") + ;; Make sure that the '.' found is not in a comment or string + (save-excursion + (end-of-line) + (re-search-backward "\\.[ \t]*\\(/\\*.*\\|\\)$" (point-min)) + ;; Guard against the real '.' being followed by a + ;; commented '.'. + (if (eq (prolog-in-string-or-comment) 'cmt) ;; commented out '.' + (let ((here (save-excursion + (beginning-of-line) + (point)))) + (end-of-line) + (re-search-backward "\\.[ \t]*/\\*.*$" here t)) + (not (prolog-in-string-or-comment)) + ) + )) + (setq ind 0)) + + ) + + ;; If the last non comment char is a ',' or left paren or a left- + ;; indent-regexp then indent to open parenthesis level + (if (and + (> totbal 0) + ;; SICStus objects have special syntax rules if point is + ;; not inside additional parens (objects are defined + ;; within {...}) + (not (and (eq prolog-system 'sicstus) + (= totbal 1) + (prolog-in-object)))) + (if (looking-at + (format "\\(%s\\|%s\\|0'.\\|[0-9]+'[0-9a-zA-Z]+\\|[^\n\'\"%%]\\)*\\(,\\|%s\\|%s\\)\[ \t]*\\(%%.*\\|\\)$" + prolog-quoted-atom-regexp prolog-string-regexp + prolog-left-paren prolog-left-indent-regexp)) + (progn + (goto-char oldpoint) + (setq ind (prolog-find-unmatched-paren (if prolog-paren-indent-p + 'termdependent + 'skipwhite))) + ;;(setq ind (prolog-find-unmatched-paren 'termdependent)) + ) + (goto-char oldpoint) + (setq ind (prolog-find-unmatched-paren nil)) + )) + + + ;; Return the indentation level + ind + )))))) + +(defun prolog-find-indent-of-matching-paren () + "Find the indentation level based on the matching parenthesis. +Indentation level is set to the one the point is after when the function is +called." + (save-excursion + ;; Go to the matching paren + (if prolog-use-prolog-tokenizer-flag + (prolog-backward-list) + (backward-list)) + + ;; If this was the first paren on the line then return this line's + ;; indentation level + (if (prolog-paren-is-the-first-on-line-p) + (prolog-indentation-level-of-line) + ;; It was not the first one + (progn + ;; Find the next paren + (prolog-goto-next-paren 0) + + ;; If this paren is a left one then use its column as indent level, + ;; if not then recurse this function + (if (looking-at prolog-left-paren) + (+ (current-column) 1) + (progn + (forward-char 1) + (prolog-find-indent-of-matching-paren))) + )) + )) + +(defun prolog-indentation-level-of-line () + "Return the indentation level of the current line." + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (current-column))) + +(defun prolog-first-pos-on-line () + "Return the first position on the current line." + (save-excursion + (beginning-of-line) + (point))) + +(defun prolog-paren-is-the-first-on-line-p () + "Return t if the parenthesis under the point is the first one on the line. +Return nil otherwise. +Note: does not check if the point is actually at a parenthesis!" + (save-excursion + (let ((begofline (prolog-first-pos-on-line))) + (if (= begofline (point)) + t + (if (prolog-goto-next-paren begofline) + nil + t))))) + +(defun prolog-find-unmatched-paren (&optional mode) + "Return the column of the last unmatched left parenthesis. +If MODE is `skipwhite' then any white space after the parenthesis is added to +the answer. +If MODE is `plusone' then the parenthesis' column +1 is returned. +If MODE is `termdependent' then if the unmatched parenthesis is part of +a compound term the function will work as `skipwhite', otherwise +it will return the column paren plus the value of `prolog-paren-indent'. +If MODE is nil or not set then the parenthesis' exact column is returned." + (save-excursion + ;; If the next paren we find is a left one we're finished, if it's + ;; a right one then we go back one step and recurse + (prolog-goto-next-paren 0) + + (let ((roundparen (looking-at "("))) + (if (looking-at prolog-left-paren) + (let ((not-part-of-term + (save-excursion + (backward-char 1) + (looking-at "[ \t]")))) + (if (eq mode nil) + (current-column) + (if (and roundparen + (eq mode 'termdependent) + not-part-of-term) + (+ (current-column) + (if prolog-electric-tab-flag + ;; Electric TAB + prolog-paren-indent + ;; Not electric TAB + (if (looking-at ".[ \t]*$") + 2 + prolog-paren-indent)) + ) + + (forward-char 1) + (if (or (eq mode 'skipwhite) (eq mode 'termdependent) ) + (skip-chars-forward " \t")) + (current-column)))) + ;; Not looking at left paren + (progn + (forward-char 1) + ;; Go to the matching paren. When we get there we have a total + ;; balance of 0. + (if prolog-use-prolog-tokenizer-flag + (prolog-backward-list) + (backward-list)) + (prolog-find-unmatched-paren mode))) + ))) + + +(defun prolog-paren-balance () + "Return the parenthesis balance of the current line. +A return value of n means n more left parentheses than right ones." + (save-excursion + (end-of-line) + (prolog-region-paren-balance (prolog-first-pos-on-line) (point)))) + +(defun prolog-region-paren-balance (beg end) + "Return the summed parenthesis balance in the region. +The region is limited by BEG and END positions." + (save-excursion + (let ((state (if prolog-use-prolog-tokenizer-flag + (prolog-tokenize beg end) + (parse-partial-sexp beg end)))) + (nth 0 state)))) + +(defun prolog-goto-next-paren (limit-pos) + "Move the point to the next parenthesis earlier in the buffer. +Return t if a match was found before LIMIT-POS. Return nil otherwise." + (let (retval) + (setq retval (re-search-backward + (concat prolog-left-paren "\\|" prolog-right-paren) + limit-pos t)) + + ;; If a match was found but it was in a string or comment, then recurse + (if (and retval (prolog-in-string-or-comment)) + (prolog-goto-next-paren limit-pos) + retval) + )) + +(defun prolog-in-string-or-comment () + "Check whether string, atom, or comment is under current point. +Return: + `txt' if the point is in a string, atom, or character code expression + `cmt' if the point is in a comment + nil otherwise." + (save-excursion + (let* ((start + (if (eq prolog-parse-mode 'beg-of-line) + ;; 'beg-of-line + (save-excursion + (let (safepoint) + (beginning-of-line) + (setq safepoint (point)) + (while (and (> (point) (point-min)) + (progn + (forward-line -1) + (end-of-line) + (if (not (bobp)) + (backward-char 1)) + (looking-at "\\\\")) + ) + (beginning-of-line) + (setq safepoint (point))) + safepoint)) + ;; 'beg-of-clause + (prolog-clause-start))) + (end (point)) + (state (if prolog-use-prolog-tokenizer-flag + (prolog-tokenize start end) + (parse-partial-sexp start end)))) + (cond + ((nth 3 state) 'txt) ; String + ((nth 4 state) 'cmt) ; Comment + (t + (cond + ((looking-at "%") 'cmt) ; Start of a comment + ((looking-at "/\\*") 'cmt) ; Start of a comment + ((looking-at "\'") 'txt) ; Start of an atom + ((looking-at "\"") 'txt) ; Start of a string + (t nil) + )))) + )) + +(defun prolog-find-start-of-mline-comment () + "Return the start column of a /* */ comment. +This assumes that the point is inside a comment." + (re-search-backward "/\\*" (point-min) t) + (forward-char 2) + (skip-chars-forward " \t") + (current-column)) + +(defun prolog-insert-spaces-after-paren () + "Insert spaces after the opening parenthesis, \"then\" (->) and \"else\" (;) branches. +Spaces are inserted if all preceding objects on the line are +whitespace characters, parentheses, or then/else branches." + (save-excursion + (let ((regexp (concat "(\\|" prolog-left-indent-regexp)) + level) + (beginning-of-line) + (skip-chars-forward " \t") + (when (looking-at regexp) + ;; Treat "( If -> " lines specially. + ;;(if (looking-at "(.*->") + ;; (setq incr 2) + ;; (setq incr prolog-paren-indent)) + + ;; work on all subsequent "->", "(", ";" + (while (looking-at regexp) + (goto-char (match-end 0)) + (setq level (+ (prolog-find-unmatched-paren) prolog-paren-indent)) + + ;; Remove old white space + (let ((start (point))) + (skip-chars-forward " \t") + (delete-region start (point))) + (indent-to level) + (skip-chars-forward " \t")) + ))) + (when (save-excursion + (backward-char 2) + (looking-at "\\s ;\\|\\s (\\|->")) ; (looking-at "\\s \\((\\|;\\)")) + (skip-chars-forward " \t")) + ) + +;;;; Comment filling + +(defun prolog-comment-limits () + "Returns the current comment limits plus the comment type (block or line). +The comment limits are the range of a block comment or the range that +contains all adjacent line comments (i.e. all comments that starts in +the same column with no empty lines or non-whitespace characters +between them)." +(let ((here (point)) + lit-limits-b lit-limits-e lit-type beg end + ) + (save-restriction + ;; Widen to catch comment limits correctly. + (widen) + (setq end (save-excursion (end-of-line) (point)) + beg (save-excursion (beginning-of-line) (point))) + (save-excursion + (beginning-of-line) + (setq lit-type (if (search-forward-regexp "%" end t) 'line 'block)) + ; (setq lit-type 'line) + ;(if (search-forward-regexp "^[ \t]*%" end t) + ; (setq lit-type 'line) + ; (if (not (search-forward-regexp "%" end t)) + ; (setq lit-type 'block) + ; (if (not (= (forward-line 1) 0)) + ; (setq lit-type 'block) + ; (setq done t + ; ret (prolog-comment-limits))) + ; )) + (if (eq lit-type 'block) + (progn + (goto-char here) + (when (looking-at "/\\*") (forward-char 2)) + (when (and (looking-at "\\*") (> (point) (point-min)) + (forward-char -1) (looking-at "/")) + (forward-char 1)) + (when (save-excursion (search-backward "/*" nil t)) + (list (save-excursion (search-backward "/*") (point)) + (or (search-forward "*/" nil t) (point-max)) lit-type))) + ;; line comment + (setq lit-limits-b (- (point) 1) + lit-limits-e end) + (condition-case nil + (if (progn (goto-char lit-limits-b) + (looking-at "%")) + (let ((col (current-column)) done) + (setq beg (point) + end lit-limits-e) + ;; Always at the beginning of the comment + ;; Go backward now + (beginning-of-line) + (while (and (zerop (setq done (forward-line -1))) + (search-forward-regexp "^[ \t]*%" (save-excursion (end-of-line) (point)) t) + (= (+ 1 col) (current-column))) + (setq beg (- (point) 1))) + (when (= done 0) + (forward-line 1)) + ;; We may have a line with code above... + (when (and (zerop (setq done (forward-line -1))) + (search-forward "%" (save-excursion (end-of-line) (point)) t) + (= (+ 1 col) (current-column))) + (setq beg (- (point) 1))) + (when (= done 0) + (forward-line 1)) + ;; Go forward + (goto-char lit-limits-b) + (beginning-of-line) + (while (and (zerop (forward-line 1)) + (search-forward-regexp "^[ \t]*%" (save-excursion (end-of-line) (point)) t) + (= (+ 1 col) (current-column))) + (setq end (save-excursion (end-of-line) (point)))) + (list beg end lit-type)) + (list lit-limits-b lit-limits-e lit-type) + ) + (error (list lit-limits-b lit-limits-e lit-type)))) + )))) + +(defun prolog-guess-fill-prefix () + ;; fill 'txt entities? + (when (save-excursion + (end-of-line) + (equal (prolog-in-string-or-comment) 'cmt)) + (let* ((bounds (prolog-comment-limits)) + (cbeg (car bounds)) + (type (nth 2 bounds)) + beg end str) + (save-excursion + (end-of-line) + (setq end (point)) + (beginning-of-line) + (setq beg (point)) + (if (and (eq type 'line) + (> cbeg beg) + (save-excursion (not (search-forward-regexp "^[ \t]*%" cbeg t)))) + (progn + (goto-char cbeg) + (search-forward-regexp "%+[ \t]*" end t) + (setq str (replace-in-string (buffer-substring beg (point)) "[^ \t%]" " ")) + ) + ;(goto-char beg) + (if (search-forward-regexp "^[ \t]*\\(%+\\|\\*+\\|/\\*+\\)[ \t]*" end t) + (setq str (replace-in-string (buffer-substring beg (point)) "/" " ")) + (beginning-of-line) + (when (search-forward-regexp "^[ \t]+" end t) + (setq str (buffer-substring beg (point))))) + )) + str))) + +(defun prolog-fill-paragraph () + "Fill paragraph comment at or after point." + (interactive) + (let* ((bounds (prolog-comment-limits)) + (type (nth 2 bounds))) + (if (eq type 'line) + (let ((fill-prefix (prolog-guess-fill-prefix))) + (fill-paragraph nil)) + (save-excursion + (save-restriction + ;; exclude surrounding lines that delimit a multiline comment + ;; and don't contain alphabetic characters, like "/*******", + ;; "- - - */" etc. + (save-excursion + (backward-paragraph) + (unless (bobp) (forward-line)) + (if (string-match "^/\\*[^a-zA-Z]*$" (thing-at-point 'line)) + (narrow-to-region (point-at-eol) (point-max)))) + (save-excursion + (forward-paragraph) + (forward-line -1) + (if (string-match "^[^a-zA-Z]*\\*/$" (thing-at-point 'line)) + (narrow-to-region (point-min) (point-at-bol)))) + (let ((fill-prefix (prolog-guess-fill-prefix))) + (fill-paragraph nil)))) + ))) + +(defun prolog-do-auto-fill () + "Carry out Auto Fill for Prolog mode. +In effect it sets the fill-prefix when inside comments and then calls +`do-auto-fill'." + (let ((fill-prefix (prolog-guess-fill-prefix))) + (do-auto-fill) + )) + +(unless (fboundp 'replace-in-string) + (defun replace-in-string (str regexp newtext &optional literal) + "Replace all matches in STR for REGEXP with NEWTEXT string, + and returns the new string. +Optional LITERAL non-nil means do a literal replacement. +Otherwise treat `\\' in NEWTEXT as special: + `\\&' in NEWTEXT means substitute original matched text. + `\\N' means substitute what matched the Nth `\\(...\\)'. + If Nth parens didn't match, substitute nothing. + `\\\\' means insert one `\\'. + `\\u' means upcase the next character. + `\\l' means downcase the next character. + `\\U' means begin upcasing all following characters. + `\\L' means begin downcasing all following characters. + `\\E' means terminate the effect of any `\\U' or `\\L'." + (if (> (length str) 50) + (let ((cfs case-fold-search)) + (with-temp-buffer + (setq case-fold-search cfs) + (insert str) + (goto-char 1) + (while (re-search-forward regexp nil t) + (replace-match newtext t literal)) + (buffer-string))) + (let ((start 0) newstr) + (while (string-match regexp str start) + (setq newstr (replace-match newtext t literal str) + start (+ (match-end 0) (- (length newstr) (length str))) + str newstr)) + str))) + ) + + + +;;------------------------------------------------------------------- +;; The tokenizer +;;------------------------------------------------------------------- + +(defconst prolog-tokenize-searchkey + (concat "[0-9]+'" + "\\|" + "['\"]" + "\\|" + prolog-left-paren + "\\|" + prolog-right-paren + "\\|" + "%" + "\\|" + "/\\*" + )) + +(defun prolog-tokenize (beg end &optional stopcond) + "Tokenize a region of prolog code between BEG and END. +STOPCOND decides the stop condition of the parsing. Valid values +are 'zerodepth which stops the parsing at the first right parenthesis +where the parenthesis depth is zero, 'skipover which skips over +the current entity (e.g. a list, a string, etc.) and nil. + +The function returns a list with the following information: + 0. parenthesis depth + 3. 'atm if END is inside an atom + 'str if END is inside a string + 'chr if END is in a character code expression (0'x) + nil otherwise + 4. non-nil if END is inside a comment + 5. end position (always equal to END if STOPCOND is nil) +The rest of the elements are undefined." + (save-excursion + (let* ((end2 (1+ end)) + oldp + (depth 0) + (quoted nil) + inside_cmt + (endpos end2) + skiptype ; The type of entity we'll skip over + ) + (goto-char beg) + + (if (and (eq stopcond 'skipover) + (looking-at "[^[({'\"]")) + (setq endpos (point)) ; Stay where we are + (while (and + (re-search-forward prolog-tokenize-searchkey end2 t) + (< (point) end2)) + (progn + (setq oldp (point)) + (goto-char (match-beginning 0)) + (cond + ;; Atoms and strings + ((looking-at "'") + ;; Find end of atom + (if (re-search-forward "[^\\]'" end2 'limit) + ;; Found end of atom + (progn + (setq oldp end2) + (if (and (eq stopcond 'skipover) + (not skiptype)) + (setq endpos (point)) + (setq oldp (point)))) ; Continue tokenizing + (setq quoted 'atm))) + + ((looking-at "\"") + ;; Find end of string + (if (re-search-forward "[^\\]\"" end2 'limit) + ;; Found end of string + (progn + (setq oldp end2) + (if (and (eq stopcond 'skipover) + (not skiptype)) + (setq endpos (point)) + (setq oldp (point)))) ; Continue tokenizing + (setq quoted 'str))) + + ;; Paren stuff + ((looking-at prolog-left-paren) + (setq depth (1+ depth)) + (setq skiptype 'paren)) + + ((looking-at prolog-right-paren) + (setq depth (1- depth)) + (if (and + (or (eq stopcond 'zerodepth) + (and (eq stopcond 'skipover) + (eq skiptype 'paren))) + (= depth 0)) + (progn + (setq endpos (1+ (point))) + (setq oldp end2)))) + + ;; Comment stuff + ((looking-at comment-start) + (end-of-line) + ;; (if (>= (point) end2) + (if (>= (point) end) + (progn + (setq inside_cmt t) + (setq oldp end2)) + (setq oldp (point)))) + + ((looking-at "/\\*") + (if (re-search-forward "\\*/" end2 'limit) + (setq oldp (point)) + (setq inside_cmt t) + (setq oldp end2))) + + ;; 0'char + ((looking-at "0'") + (setq oldp (1+ (match-end 0))) + (if (> oldp end) + (setq quoted 'chr))) + + ;; base'number + ((looking-at "[0-9]+'") + (goto-char (match-end 0)) + (skip-chars-forward "0-9a-zA-Z") + (setq oldp (point))) + + + ) + (goto-char oldp) + )) ; End of while + ) + + ;; Deal with multi-line comments + (and (prolog-inside-mline-comment end) + (setq inside_cmt t)) + + ;; Create return list + (list depth nil nil quoted inside_cmt endpos) + ))) + +(defun prolog-inside-mline-comment (here) + (save-excursion + (goto-char here) + (let* ((next-close (save-excursion (search-forward "*/" nil t))) + (next-open (save-excursion (search-forward "/*" nil t))) + (prev-open (save-excursion (search-backward "/*" nil t))) + (prev-close (save-excursion (search-backward "*/" nil t))) + (unmatched-next-close (and next-close + (or (not next-open) + (> next-open next-close)))) + (unmatched-prev-open (and prev-open + (or (not prev-close) + (> prev-open prev-close)))) + ) + (or unmatched-next-close unmatched-prev-open) + ))) + + +;;------------------------------------------------------------------- +;; Online help +;;------------------------------------------------------------------- + +(defvar prolog-help-function + '((mercury nil) + (eclipse prolog-help-online) + ;; (sicstus prolog-help-info) + (sicstus prolog-find-documentation) + (swi prolog-help-online) + (t prolog-help-online)) + "Alist for the name of the function for finding help on a predicate.") + +(defun prolog-help-on-predicate () + "Invoke online help on the atom under cursor." + (interactive) + + (cond + ;; Redirect help for SICStus to `prolog-find-documentation'. + ((eq prolog-help-function-i 'prolog-find-documentation) + (prolog-find-documentation)) + + ;; Otherwise, ask for the predicate name and then call the function + ;; in prolog-help-function-i + (t + (let* (word + predicate + ;point + ) + (setq word (prolog-atom-under-point)) + (setq predicate (read-from-minibuffer + (format "Help on predicate%s: " + (if word + (concat " (default " word ")") + "")))) + (if (string= predicate "") + (setq predicate word)) + (if prolog-help-function-i + (funcall prolog-help-function-i predicate) + (error "Sorry, no help method defined for this Prolog system.")))) + )) + +(defun prolog-help-info (predicate) + (let ((buffer (current-buffer)) + oldp + (str (concat "^\\* " (regexp-quote predicate) " */"))) + (require 'info) + (pop-to-buffer nil) + (Info-goto-node prolog-info-predicate-index) + (if (not (re-search-forward str nil t)) + (error (format "Help on predicate `%s' not found." predicate))) + + (setq oldp (point)) + (if (re-search-forward str nil t) + ;; Multiple matches, ask user + (let ((max 2) + n) + ;; Count matches + (while (re-search-forward str nil t) + (setq max (1+ max))) + + (goto-char oldp) + (re-search-backward "[^ /]" nil t) + (recenter 0) + (setq n (read-string ;; was read-input, which is obsolete + (format "Several matches, choose (1-%d): " max) "1")) + (forward-line (- (string-to-number n) 1))) + ;; Single match + (re-search-backward "[^ /]" nil t)) + + ;; (Info-follow-nearest-node (point)) + (prolog-Info-follow-nearest-node) + (re-search-forward (concat "^`" (regexp-quote predicate)) nil t) + (beginning-of-line) + (recenter 0) + (pop-to-buffer buffer))) + +(defun prolog-Info-follow-nearest-node () + (if (eq prolog-emacs 'xemacs) + (Info-follow-nearest-node (point)) + (Info-follow-nearest-node)) +) + +(defun prolog-help-online (predicate) + (prolog-ensure-process) + (process-send-string "prolog" (concat "help(" predicate ").\n")) + (display-buffer "*prolog*")) + +(defun prolog-help-apropos (string) + "Find Prolog apropos on given STRING. +This function is only available when `prolog-system' is set to `swi'." + (interactive "sApropos: ") + (cond + ((eq prolog-system 'swi) + (prolog-ensure-process) + (process-send-string "prolog" (concat "apropos(" string ").\n")) + (display-buffer "*prolog*")) + (t + (error "Sorry, no Prolog apropos available for this Prolog system.")))) + +(defun prolog-atom-under-point () + "Return the atom under or left to the point." + (save-excursion + (let ((nonatom_chars "[](){},\. \t\n") + start) + (skip-chars-forward (concat "^" nonatom_chars)) + (skip-chars-backward nonatom_chars) + (skip-chars-backward (concat "^" nonatom_chars)) + (setq start (point)) + (skip-chars-forward (concat "^" nonatom_chars)) + (buffer-substring-no-properties start (point)) + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Help function with completion +;; Stolen from Per Mildner's SICStus debugger mode and modified + +(defun prolog-find-documentation () + "Go to the Info node for a predicate in the SICStus Info manual." + (interactive) + (let ((pred (prolog-read-predicate))) + (prolog-goto-predicate-info pred))) + +(defvar prolog-info-alist nil + "Alist with all builtin predicates. +Only for internal use by `prolog-find-documentation'") + +;; Very similar to prolog-help-info except that that function cannot +;; cope with arity and that it asks the user if there are several +;; functors with different arity. This function also uses +;; prolog-info-alist for finding the info node, rather than parsing +;; the predicate index. +(defun prolog-goto-predicate-info (predicate) + "Go to the info page for PREDICATE, which is a PredSpec." + (interactive) + (require 'info) + (string-match "\\(.*\\)/\\([0-9]+\\).*$" predicate) + (let ((buffer (current-buffer)) + (name (match-string 1 predicate)) + (arity (match-string 2 predicate)) + ;oldp + ;(str (regexp-quote predicate)) + ) + (setq arity (string-to-number arity)) + (pop-to-buffer nil) + + (Info-goto-node + prolog-info-predicate-index) ;; We must be in the SICStus pages + (Info-goto-node (car (cdr (assoc predicate prolog-info-alist)))) + + (prolog-find-term (regexp-quote name) arity "^`") + + (recenter 0) + (pop-to-buffer buffer)) +) + +(defun prolog-read-predicate () + "Read a PredSpec from the user. +Returned value is a string \"FUNCTOR/ARITY\". +Interaction supports completion." + (let ((initial (prolog-atom-under-point)) + answer) + ;; If the predicate index is not yet built, do it now + (if (not prolog-info-alist) + (prolog-build-info-alist)) + ;; Test if the initial string could be the base for completion. + ;; Discard it if not. + (if (eq (try-completion initial prolog-info-alist) nil) + (setq initial "")) + ;; Read the PredSpec from the user + (setq answer (completing-read + "Help on predicate: " + prolog-info-alist nil t initial)) + (if (equal answer "") + initial + answer))) + +(defun prolog-build-info-alist (&optional verbose) + "Build an alist of all builtins and library predicates. +Each element is of the form (\"NAME/ARITY\" . (INFO-NODE1 INFO-NODE2 ...)). +Typically there is just one Info node associated with each name +If an optional argument VERBOSE is non-nil, print messages at the beginning +and end of list building." + (if verbose + (message "Building info alist...")) + (setq prolog-info-alist + (let ((l ()) + (last-entry (cons "" ()))) + (save-excursion + (save-window-excursion + ;; select any window but the minibuffer (as we cannot switch + ;; buffers in minibuffer window. + ;; I am not sure this is the right/best way + (if (active-minibuffer-window) ; nil if none active + (select-window (next-window))) + ;; Do this after going away from minibuffer window + (save-window-excursion + (info)) + (Info-goto-node prolog-info-predicate-index) + (goto-char (point-min)) + (while (re-search-forward + "^\\* \\(.+\\)/\\([0-9]+\\)\\([^\n:*]*\\):" nil t) + (let* ((name (match-string 1)) + (arity (string-to-number (match-string 2))) + (comment (match-string 3)) + (fa (format "%s/%d%s" name arity comment)) + info-node) + (beginning-of-line) + ;; Extract the info node name + (setq info-node (progn + (re-search-forward ":[ \t]*\\([^:]+\\).$") + (match-string 1) + )) + ;; ###### Easier? (from Milan version 0.1.28) + ;; (setq info-node (Info-extract-menu-node-name)) + (if (equal fa (car last-entry)) + (setcdr last-entry (cons info-node (cdr last-entry))) + (setq last-entry (cons fa (list info-node)) + l (cons last-entry l))))) + (nreverse l) + )))) + (if verbose + (message "Building info alist... done."))) + + +;;------------------------------------------------------------------- +;; Miscellaneous functions +;;------------------------------------------------------------------- + +;; For Windows. Change backslash to slash. SICStus handles either +;; path separator but backslash must be doubled, therefore use slash. +(defun prolog-bsts (string) + "Change backslashes to slashes in STRING." + (let ((str1 (copy-sequence string)) + (len (length string)) + (i 0)) + (while (< i len) + (if (char-equal (aref str1 i) ?\\) + (aset str1 i ?/)) + (setq i (1+ i))) + str1)) + +;(defun prolog-temporary-file () +; "Make temporary file name for compilation." +; (make-temp-name +; (concat +; (or +; (getenv "TMPDIR") +; (getenv "TEMP") +; (getenv "TMP") +; (getenv "SYSTEMP") +; "/tmp") +; "/prolcomp"))) +;(setq prolog-temp-filename (prolog-bsts (prolog-temporary-file))) + +(defun prolog-temporary-file () + "Make temporary file name for compilation." + (if prolog-temporary-file-name + ;; We already have a file, erase content and continue + (progn + (write-region "" nil prolog-temporary-file-name nil 'silent) + prolog-temporary-file-name) + ;; Actually create the file and set `prolog-temporary-file-name' accordingly + (let* ((umask (default-file-modes)) + (temporary-file-directory (or + (getenv "TMPDIR") + (getenv "TEMP") + (getenv "TMP") + (getenv "SYSTEMP") + "/tmp")) + (prefix (expand-file-name "prolcomp" temporary-file-directory)) + (suffix ".pl") + file) + (unwind-protect + (progn + ;; Create temp files with strict access rights. + (set-default-file-modes #o700) + (while (condition-case () + (progn + (setq file (concat (make-temp-name prefix) suffix)) + ;; (concat (make-temp-name "/tmp/prolcomp") ".pl") + (unless (file-exists-p file) + (write-region "" nil file nil 'silent)) + nil) + (file-already-exists t)) + ;; the file was somehow created by someone else between + ;; `make-temp-name' and `write-region', let's try again. + nil) + (setq prolog-temporary-file-name file)) + ;; Reset the umask. + (set-default-file-modes umask))) + )) + +(defun prolog-goto-prolog-process-buffer () + "Switch to the prolog process buffer and go to its end." + (switch-to-buffer-other-window "*prolog*") + (goto-char (point-max)) +) + +(defun prolog-enable-sicstus-sd () + "Enable the source level debugging facilities of SICStus 3.7 and later." + (interactive) + (require 'pltrace) ; Load the SICStus debugger code + ;; Turn on the source level debugging by default + (add-hook 'prolog-inferior-mode-hook 'pltrace-on) + (if (not prolog-use-sicstus-sd) + (progn + ;; If there is a *prolog* buffer, then call pltrace-on + (if (get-buffer "*prolog*") + ;; Avoid compilation warnings by using eval + (eval '(pltrace-on))) + (setq prolog-use-sicstus-sd t) + )) + ) + +(defun prolog-disable-sicstus-sd () + "Disable the source level debugging facilities of SICStus 3.7 and later." + (interactive) + (setq prolog-use-sicstus-sd nil) + ;; Remove the hook + (remove-hook 'prolog-inferior-mode-hook 'pltrace-on) + ;; If there is a *prolog* buffer, then call pltrace-off + (if (get-buffer "*prolog*") + ;; Avoid compile warnings by using eval + (eval '(pltrace-off)))) + +(defun prolog-debug-on (&optional arg) + "Enable debugging. +When called with prefix argument ARG, disable debugging instead." + (interactive "P") + (if arg + (prolog-debug-off) + (prolog-process-insert-string (get-process "prolog") + prolog-debug-on-string) + (process-send-string "prolog" prolog-debug-on-string))) + +(defun prolog-debug-off () + "Disable debugging." + (interactive) + (prolog-process-insert-string (get-process "prolog") + prolog-debug-off-string) + (process-send-string "prolog" prolog-debug-off-string)) + +(defun prolog-trace-on (&optional arg) + "Enable tracing. +When called with prefix argument ARG, disable tracing instead." + (interactive "P") + (if arg + (prolog-trace-off) + (prolog-process-insert-string (get-process "prolog") + prolog-trace-on-string) + (process-send-string "prolog" prolog-trace-on-string))) + +(defun prolog-trace-off () + "Disable tracing." + (interactive) + (prolog-process-insert-string (get-process "prolog") + prolog-trace-off-string) + (process-send-string "prolog" prolog-trace-off-string)) + +(defun prolog-zip-on (&optional arg) + "Enable zipping (for SICStus 3.7 and later). +When called with prefix argument ARG, disable zipping instead." + (interactive "P") + (if arg + (prolog-zip-off) + (prolog-process-insert-string (get-process "prolog") + prolog-zip-on-string) + (process-send-string "prolog" prolog-zip-on-string))) + +(defun prolog-zip-off () + "Disable zipping (for SICStus 3.7 and later)." + (interactive) + (prolog-process-insert-string (get-process "prolog") + prolog-zip-off-string) + (process-send-string "prolog" prolog-zip-off-string)) + +;; (defun prolog-create-predicate-index () +;; "Create an index for all predicates in the buffer." +;; (let ((predlist '()) +;; clauseinfo +;; object +;; pos +;; ) +;; (goto-char (point-min)) +;; ;; Replace with prolog-clause-start! +;; (while (re-search-forward "^.+:-" nil t) +;; (setq pos (match-beginning 0)) +;; (setq clauseinfo (prolog-clause-info)) +;; (setq object (prolog-in-object)) +;; (setq predlist (append +;; predlist +;; (list (cons +;; (if (and (eq prolog-system 'sicstus) +;; (prolog-in-object)) +;; (format "%s::%s/%d" +;; object +;; (nth 0 clauseinfo) +;; (nth 1 clauseinfo)) +;; (format "%s/%d" +;; (nth 0 clauseinfo) +;; (nth 1 clauseinfo))) +;; pos +;; )))) +;; (prolog-end-of-predicate)) +;; predlist)) + +(defun prolog-get-predspec () + (save-excursion + (let ((state (prolog-clause-info)) + (object (prolog-in-object))) + (if (or (equal (nth 0 state) "") (equal (prolog-in-string-or-comment) 'cmt)) + nil + (if (and (eq prolog-system 'sicstus) + object) + (format "%s::%s/%d" + object + (nth 0 state) + (nth 1 state)) + (format "%s/%d" + (nth 0 state) + (nth 1 state))) + )))) + +;; For backward compatibility. Stolen from custom.el. +(or (fboundp 'match-string) + ;; Introduced in Emacs 19.29. + (defun match-string (num &optional string) + "Return string of text matched by last search. +NUM specifies which parenthesized expression in the last regexp. + Value is nil if NUMth pair didn't match, or there were less than NUM pairs. +Zero means the entire text matched by the whole regexp or whole string. +STRING should be given if the last search was by `string-match' on STRING." + (if (match-beginning num) + (if string + (substring string (match-beginning num) (match-end num)) + (buffer-substring (match-beginning num) (match-end num)))))) + +(defun prolog-pred-start () + "Return the starting point of the first clause of the current predicate." + (save-excursion + (goto-char (prolog-clause-start)) + ;; Find first clause, unless it was a directive + (if (and (not (looking-at "[:?]-")) + (not (looking-at "[ \t]*[%/]")) ; Comment + + ) + (let* ((pinfo (prolog-clause-info)) + (predname (nth 0 pinfo)) + (arity (nth 1 pinfo)) + (op (point))) + (while (and (re-search-backward + (format "^%s\\([(\\.]\\| *%s\\)" + predname prolog-head-delimiter) nil t) + (= arity (nth 1 (prolog-clause-info))) + ) + (setq op (point))) + (if (eq prolog-system 'mercury) + ;; Skip to the beginning of declarations of the predicate + (progn + (goto-char (prolog-beginning-of-clause)) + (while (and (not (eq (point) op)) + (looking-at + (format ":-[ \t]*\\(pred\\|mode\\)[ \t]+%s" + predname))) + (setq op (point)) + (goto-char (prolog-beginning-of-clause))))) + op) + (point)))) + +(defun prolog-pred-end () + "Return the position at the end of the last clause of the current predicate." + (save-excursion + (goto-char (prolog-clause-end)) ; if we are before the first predicate + (goto-char (prolog-clause-start)) + (let* ((pinfo (prolog-clause-info)) + (predname (nth 0 pinfo)) + (arity (nth 1 pinfo)) + oldp + (notdone t) + (op (point))) + (if (looking-at "[:?]-") + ;; This was a directive + (progn + (if (and (eq prolog-system 'mercury) + (looking-at + (format ":-[ \t]*\\(pred\\|mode\\)[ \t]+\\(%s+\\)" + prolog-atom-regexp))) + ;; Skip predicate declarations + (progn + (setq predname (buffer-substring-no-properties + (match-beginning 2) (match-end 2))) + (while (re-search-forward + (format + "\n*\\(:-[ \t]*\\(pred\\|mode\\)[ \t]+\\)?%s[( \t]" + predname) + nil t)))) + (goto-char (prolog-clause-end)) + (setq op (point))) + ;; It was not a directive, find the last clause + (while (and notdone + (re-search-forward + (format "^%s\\([(\\.]\\| *%s\\)" + predname prolog-head-delimiter) nil t) + (= arity (nth 1 (prolog-clause-info)))) + (setq oldp (point)) + (setq op (prolog-clause-end)) + (if (>= oldp op) + ;; End of clause not found. + (setq notdone nil) + ;; Continue while loop + (goto-char op)))) + op))) + +(defun prolog-clause-start (&optional not-allow-methods) + "Return the position at the start of the head of the current clause. +If NOTALLOWMETHODS is non-nil then do not match on methods in +objects (relevent only if 'prolog-system' is set to 'sicstus)." + (save-excursion + (let ((notdone t) + (retval (point-min))) + (end-of-line) + + ;; SICStus object? + (if (and (not not-allow-methods) + (eq prolog-system 'sicstus) + (prolog-in-object)) + (while (and + notdone + ;; Search for a head or a fact + (re-search-backward + ;; If in object, then find method start. + ;; "^[ \t]+[a-z$].*\\(:-\\|&\\|:: {\\|,\\)" + "^[ \t]+[a-z$].*\\(:-\\|&\\|:: {\\)" ; The comma causes + ; problems since we cannot assume + ; that the line starts at column 0, + ; thus we don't know if the line + ; is a head or a subgoal + (point-min) t)) + (if (>= (prolog-paren-balance) 0) ; To no match on " a) :-" + ;; Start of method found + (progn + (setq retval (point)) + (setq notdone nil))) + ) ; End of while + + ;; Not in object + (while (and + notdone + ;; Search for a text at beginning of a line + ;; ###### + ;; (re-search-backward "^[a-z$']" nil t)) + (let ((case-fold-search nil)) + (re-search-backward + ;; (format "^[%s$']" prolog-lower-case-string) + (format "^\\([%s$']\\|[:?]-\\)" prolog-lower-case-string) + nil t))) + (let ((bal (prolog-paren-balance))) + (cond + ((> bal 0) + ;; Start of clause found + (progn + (setq retval (point)) + (setq notdone nil))) + ((and (= bal 0) + (looking-at + (format ".*\\(\\.\\|%s\\|!,\\)[ \t]*\\(%%.*\\|\\)$" + prolog-head-delimiter))) + ;; Start of clause found if the line ends with a '.' or + ;; a prolog-head-delimiter + (progn + (setq retval (point)) + (setq notdone nil)) + ) + (t nil) ; Do nothing + )))) + + retval))) + +(defun prolog-clause-end (&optional not-allow-methods) + "Return the position at the end of the current clause. +If NOTALLOWMETHODS is non-nil then do not match on methods in +objects (relevent only if 'prolog-system' is set to 'sicstus)." + (save-excursion + (beginning-of-line) ; Necessary since we use "^...." for the search + (if (re-search-forward + (if (and (not not-allow-methods) + (eq prolog-system 'sicstus) + (prolog-in-object)) + (format + "^\\(%s\\|%s\\|[^\n\'\"%%]\\)*&[ \t]*\\(\\|%%.*\\)$\\|[ \t]*}" + prolog-quoted-atom-regexp prolog-string-regexp) + (format + "^\\(%s\\|%s\\|[^\n\'\"%%]\\)*\\.[ \t]*\\(\\|%%.*\\)$" + prolog-quoted-atom-regexp prolog-string-regexp)) + nil t) + (if (and (prolog-in-string-or-comment) + (not (eobp))) + (progn + (forward-char) + (prolog-clause-end)) + (point)) + (point)))) + +(defun prolog-clause-info () + "Return a (name arity) list for the current clause." + (let (predname (arity 0)) + (save-excursion + (goto-char (prolog-clause-start)) + (let ((op (point))) + (if (looking-at prolog-atom-char-regexp) + (progn + (skip-chars-forward "^ (\\.") + (setq predname (buffer-substring op (point)))) + (setq predname "")) + ;; Retrieve the arity + (if (looking-at prolog-left-paren) + (let ((endp (save-excursion + (prolog-forward-list) (point)))) + (setq arity 1) + (forward-char 1) ; Skip the opening paren + (while (progn + (skip-chars-forward "^[({,'\"") + (< (point) endp)) + (if (looking-at ",") + (progn + (setq arity (1+ arity)) + (forward-char 1) ; Skip the comma + ) + ;; We found a string, list or something else we want + ;; to skip over. Always use prolog-tokenize, + ;; parse-partial-sexp does not have a 'skipover mode. + (goto-char (nth 5 (prolog-tokenize (point) endp 'skipover)))) + ))) + (list predname arity) + )))) + +(defun prolog-in-object () + "Return object name if the point is inside a SICStus object definition." + ;; Return object name if the last line that starts with a character + ;; that is neither white space nor a comment start + (save-excursion + (if (save-excursion + (beginning-of-line) + (looking-at "\\([^\n ]+\\)[ \t]*::[ \t]*{")) + ;; We were in the head of the object + (match-string 1) + ;; We were not in the head + (if (and (re-search-backward "^[a-z$'}]" nil t) + (looking-at "\\([^\n ]+\\)[ \t]*::[ \t]*{")) + (match-string 1) + nil)))) + +(defun prolog-forward-list () + "Move the point to the matching right parenthesis." + (interactive) + (if prolog-use-prolog-tokenizer-flag + (let ((state (prolog-tokenize (point) (point-max) 'zerodepth))) + (goto-char (nth 5 state))) + (forward-list))) + +;; NB: This could be done more efficiently! +(defun prolog-backward-list () + "Move the point to the matching left parenthesis." + (interactive) + (if prolog-use-prolog-tokenizer-flag + (let ((bal 0) + (paren-regexp (concat prolog-left-paren "\\|" prolog-right-paren)) + (notdone t)) + (while (and notdone (re-search-backward paren-regexp nil t)) + (cond + ((looking-at prolog-left-paren) + (if (not (prolog-in-string-or-comment)) + (setq bal (1+ bal))) + (if (= bal 0) + (setq notdone nil))) + ((looking-at prolog-right-paren) + (if (not (prolog-in-string-or-comment)) + (setq bal (1- bal)))) + ))) + (backward-list))) + +(defun prolog-beginning-of-clause () + "Move to the beginning of current clause. +If already at the beginning of clause, move to previous clause." + (interactive) + (let ((point (point)) + (new-point (prolog-clause-start))) + (if (and (>= new-point point) + (> point 1)) + (progn + (goto-char (1- point)) + (goto-char (prolog-clause-start))) + (goto-char new-point) + (skip-chars-forward " \t")))) + +;; (defun prolog-previous-clause () +;; "Move to the beginning of the previous clause." +;; (interactive) +;; (forward-char -1) +;; (prolog-beginning-of-clause)) + +(defun prolog-end-of-clause () + "Move to the end of clause. +If already at the end of clause, move to next clause." + (interactive) + (let ((point (point)) + (new-point (prolog-clause-end))) + (if (and (<= new-point point) + (not (eq new-point (point-max)))) + (progn + (goto-char (1+ point)) + (goto-char (prolog-clause-end))) + (goto-char new-point)))) + +;; (defun prolog-next-clause () +;; "Move to the beginning of the next clause." +;; (interactive) +;; (prolog-end-of-clause) +;; (forward-char) +;; (prolog-end-of-clause) +;; (prolog-beginning-of-clause)) + +(defun prolog-beginning-of-predicate () + "Go to the nearest beginning of predicate before current point. +Return the final point or nil if no such a beginning was found." + (interactive) + (let ((op (point)) + (pos (prolog-pred-start))) + (if pos + (if (= op pos) + (if (not (bobp)) + (progn + (goto-char pos) + (backward-char 1) + (setq pos (prolog-pred-start)) + (if pos + (progn + (goto-char pos) + (point))))) + (goto-char pos) + (point))))) + +(defun prolog-end-of-predicate () + "Go to the end of the current predicate." + (interactive) + (let ((op (point))) + (goto-char (prolog-pred-end)) + (if (= op (point)) + (progn + (forward-line 1) + (prolog-end-of-predicate))))) + +(defun prolog-insert-predspec () + "Insert the predspec for the current predicate." + (interactive) + (let* ((pinfo (prolog-clause-info)) + (predname (nth 0 pinfo)) + (arity (nth 1 pinfo))) + (insert (format "%s/%d" predname arity)))) + +(defun prolog-view-predspec () + "Insert the predspec for the current predicate." + (interactive) + (let* ((pinfo (prolog-clause-info)) + (predname (nth 0 pinfo)) + (arity (nth 1 pinfo))) + (message (format "%s/%d" predname arity)))) + +(defun prolog-insert-predicate-template () + "Insert the template for the current clause." + (interactive) + (let* ((n 1) + oldp + (pinfo (prolog-clause-info)) + (predname (nth 0 pinfo)) + (arity (nth 1 pinfo))) + (insert predname) + (if (> arity 0) + (progn + (insert "(") + (when prolog-electric-dot-full-predicate-template + (setq oldp (point)) + (while (< n arity) + (insert ",") + (setq n (1+ n))) + (insert ")") + (goto-char oldp)) + )) + )) + +(defun prolog-insert-next-clause () + "Insert newline and the name of the current clause." + (interactive) + (insert "\n") + (prolog-insert-predicate-template)) + +(defun prolog-insert-module-modeline () + "Insert a modeline for module specification. +This line should be first in the buffer. +The module name should be written manually just before the semi-colon." + (interactive) + (insert "%%% -*- Module: ; -*-\n") + (backward-char 6)) + +(defun prolog-uncomment-region (beg end) + "Uncomment the region between BEG and END." + (interactive "r") + (comment-region beg end -1)) + +(defun prolog-goto-comment-column (&optional nocreate) + "Move comments on the current line to the correct position. +If NOCREATE is nil (or omitted) and there is no comment on the line, then +a new comment is created." + (interactive) + (beginning-of-line) + (if (or (not nocreate) + (and + (re-search-forward + (format "^\\(\\(%s\\|%s\\|[^\n\'\"%%]\\)*\\)%% *" + prolog-quoted-atom-regexp prolog-string-regexp) + (save-excursion (end-of-line) (point)) 'limit) + (progn + (goto-char (match-beginning 0)) + (not (eq (prolog-in-string-or-comment) 'txt))))) + (indent-for-comment))) + +(defun prolog-indent-predicate () + "*Indent the current predicate." + (interactive) + (indent-region (prolog-pred-start) (prolog-pred-end) nil)) + +(defun prolog-indent-buffer () + "*Indent the entire buffer." + (interactive) + (indent-region (point-min) (point-max) nil)) + +(defun prolog-mark-clause () + "Put mark at the end of this clause and move point to the beginning." + (interactive) + (let ((pos (point))) + (goto-char (prolog-clause-end)) + (forward-line 1) + (beginning-of-line) + (set-mark (point)) + (goto-char pos) + (goto-char (prolog-clause-start)))) + +(defun prolog-mark-predicate () + "Put mark at the end of this predicate and move point to the beginning." + (interactive) + (let (pos) + (goto-char (prolog-pred-end)) + (setq pos (point)) + (forward-line 1) + (beginning-of-line) + (set-mark (point)) + (goto-char pos) + (goto-char (prolog-pred-start)))) + +;; Stolen from `cc-mode.el': +(defun prolog-electric-delete (arg) + "Delete preceding character or whitespace. +If `prolog-hungry-delete-key-flag' is non-nil, then all preceding whitespace is +consumed. If however an ARG is supplied, or `prolog-hungry-delete-key-flag' is +nil, or point is inside a literal then the function in the variable +`backward-delete-char' is called." + (interactive "P") + (if (or (not prolog-hungry-delete-key-flag) + arg + (prolog-in-string-or-comment)) + (funcall 'backward-delete-char (prefix-numeric-value arg)) + (let ((here (point))) + (skip-chars-backward " \t\n") + (if (/= (point) here) + (delete-region (point) here) + (funcall 'backward-delete-char 1) + )))) + +;; For XEmacs compatibility (suggested by Per Mildner) +(put 'prolog-electric-delete 'pending-delete 'supersede) + +(defun prolog-electric-if-then-else (arg) + "If `prolog-electric-if-then-else-flag' is non-nil, indent if-then-else constructs. +Bound to the >, ; and ( keys." + (interactive "P") + (self-insert-command (prefix-numeric-value arg)) + (if prolog-electric-if-then-else-flag (prolog-insert-spaces-after-paren))) + +(defun prolog-electric-colon (arg) + "If `prolog-electric-colon-flag' is non-nil, insert the electric `:' construct, +that is, space (if appropriate), `:-' and newline if colon is pressed +at the end of a line that starts in the first column (i.e., clause +heads)." + (interactive "P") + (if (and prolog-electric-colon-flag + (null arg) + (= (point) (line-end-position)) + ;(not (string-match "^\\s " (thing-at-point 'line)))) + (not (string-match "^\\(\\s \\|%\\)" (thing-at-point 'line)))) + (progn + (unless (save-excursion (backward-char 1) (looking-at "\\s ")) (insert " ")) + (insert ":-\n") + (prolog-indent-line)) + (self-insert-command (prefix-numeric-value arg)))) + +(defun prolog-electric-dash (arg) + "If `prolog-electric-dash-flag' is non-nil, insert the electric `-' construct, +that is, space (if appropriate), `-->' and newline if dash is pressed +at the end of a line that starts in the first column (i.e., DCG +heads)." + (interactive "P") + (if (and prolog-electric-dash-flag + (null arg) + (= (point) (line-end-position)) + ;(not (string-match "^\\s " (thing-at-point 'line)))) + (not (string-match "^\\(\\s \\|%\\)" (thing-at-point 'line)))) + (progn + (unless (save-excursion (backward-char 1) (looking-at "\\s ")) (insert " ")) + (insert "-->\n") + (prolog-indent-line)) + (self-insert-command (prefix-numeric-value arg)))) + +(defun prolog-electric-dot (arg) + "Insert dot and newline or a head of a new clause. + +If `prolog-electric-dot-flag' is nil, then simply insert dot. +Otherwise:: +When invoked at the end of nonempty line, insert dot and newline. +When invoked at the end of an empty line, insert a recursive call to +the current predicate. +When invoked at the beginning of line, insert a head of a new clause +of the current predicate. + +When called with prefix argument ARG, insert just dot." + (interactive "P") + ;; Check for situations when the electricity should not be active + (if (or (not prolog-electric-dot-flag) + arg + (prolog-in-string-or-comment) + ;; Do not be electric in a floating point number or an operator + (not + (or + ;; (re-search-backward + ;; ###### + ;; "\\(^\\|[])}a-zA-Z_!'0-9]+\\)[ \t]*\\=" nil t))) + (save-excursion + (re-search-backward + ;; "\\(^\\|[])}_!'0-9]+\\)[ \t]*\\=" nil t))) + "\\(^\\|[])}_!'0-9]+\\)[ \t]*\\=" + nil t)) + (save-excursion + (re-search-backward + ;; "\\(^\\|[])}a-zA-Z]+\\)[ \t]*\\=" nil t))) + (format "\\(^\\|[])}%s]+\\)[ \t]*\\=" + prolog-lower-case-string) + nil t)) + (save-excursion + (re-search-backward + ;; "\\(^\\|[])}a-zA-Z]+\\)[ \t]*\\=" nil t))) + (format "\\(^\\|[])}%s]+\\)[ \t]*\\=" + prolog-upper-case-string) + nil t)) + ) + ) + ;; Do not be electric if inside a parenthesis pair. + (not (= (prolog-region-paren-balance (prolog-clause-start) (point)) + 0)) + ) + (funcall 'self-insert-command (prefix-numeric-value arg)) + (cond + ;; Beginning of line + ((bolp) + (prolog-insert-predicate-template)) + ;; At an empty line with at least one whitespace + ((save-excursion + (beginning-of-line) + (looking-at "[ \t]+$")) + (prolog-insert-predicate-template) + (when prolog-electric-dot-full-predicate-template + (save-excursion + (end-of-line) + (insert ".\n")))) + ;; Default + (t + (insert ".\n")) + ))) + +(defun prolog-electric-underscore () + "Replace variable with an underscore. +If `prolog-electric-underscore-flag' is non-nil and the point is +on a variable then replace the variable with underscore and skip +the following comma and whitespace, if any. +If the point is not on a variable then insert underscore." + (interactive) + (if prolog-electric-underscore-flag + (let (;start + (oldcase case-fold-search) + (oldp (point))) + (setq case-fold-search nil) + ;; ###### + ;;(skip-chars-backward "a-zA-Z_") + (skip-chars-backward + (format "%s%s_" + prolog-lower-case-string + prolog-upper-case-string)) + + ;(setq start (point)) + (if (and (not (prolog-in-string-or-comment)) + ;; ###### + ;; (looking-at "\\<[_A-Z][a-zA-Z_0-9]*\\>")) + (looking-at (format "\\<[_%s][%s%s_0-9]*\\>" + prolog-upper-case-string + prolog-lower-case-string + prolog-upper-case-string))) + (progn + (replace-match "_") + (skip-chars-forward ", \t\n")) + (goto-char oldp) + (self-insert-command 1)) + (setq case-fold-search oldcase) + ) + (self-insert-command 1)) + ) + + +(defun prolog-find-term (functor arity &optional prefix) + "Go to the position at the start of the next occurance of a term. +The term is specified with FUNCTOR and ARITY. The optional argument +PREFIX is the prefix of the search regexp." + (let* (;; If prefix is not set then use the default "\\<" + (prefix (if (not prefix) + "\\<" + prefix)) + (regexp (concat prefix functor)) + (i 1)) + + ;; Build regexp for the search if the arity is > 0 + (if (= arity 0) + ;; Add that the functor must be at the end of a word. This + ;; does not work if the arity is > 0 since the closing ) + ;; is not a word constituent. + (setq regexp (concat regexp "\\>")) + ;; Arity is > 0, add parens and commas + (setq regexp (concat regexp "(")) + (while (< i arity) + (setq regexp (concat regexp ".+,")) + (setq i (1+ i))) + (setq regexp (concat regexp ".+)"))) + + ;; Search, and return position + (if (re-search-forward regexp nil t) + (goto-char (match-beginning 0)) + (error "Term not found")) + )) + +(defun prolog-variables-to-anonymous (beg end) + "Replace all variables within a region BEG to END by anonymous variables." + (interactive "r") + (save-excursion + (let ((oldcase case-fold-search)) + (setq case-fold-search nil) + (goto-char end) + (while (re-search-backward "\\<[A-Z_][a-zA-Z_0-9]*\\>" beg t) + (progn + (replace-match "_") + (backward-char))) + (setq case-fold-search oldcase) + ))) + + +(defun prolog-set-atom-regexps () + "Set the `prolog-atom-char-regexp' and `prolog-atom-regexp' variables. +Must be called after `prolog-build-case-strings'." + (setq prolog-atom-char-regexp + (format "[%s%s0-9_$]" + prolog-lower-case-string + prolog-upper-case-string)) + (setq prolog-atom-regexp + (format "[%s$]%s*" + prolog-lower-case-string + prolog-atom-char-regexp)) + ) + +(defun prolog-build-case-strings () + "Set `prolog-upper-case-string' and `prolog-lower-case-string'. +Uses the current case-table for extracting the relevant information." + (let ((up_string "") + (low_string "")) + ;; Use `map-char-table' if it is defined. Otherwise enumerate all + ;; numbers between 0 and 255. `map-char-table' is probably safer. + ;; + ;; `map-char-table' causes problems under Emacs 23.0.0.1, the + ;; while loop seems to do its job well (Ryszard Szopa) + ;; + ;;(if (and (not (eq prolog-emacs 'xemacs)) + ;; (fboundp 'map-char-table)) + ;; (map-char-table + ;; (lambda (key value) + ;; (cond + ;; ((and + ;; (eq (int-to-char key) (downcase key)) + ;; (eq (int-to-char key) (upcase key))) + ;; ;; Do nothing if upper and lower case are the same + ;; ) + ;; ((eq (int-to-char key) (downcase key)) + ;; ;; The char is lower case + ;; (setq low_string (format "%s%c" low_string key))) + ;; ((eq (int-to-char key) (upcase key)) + ;; ;; The char is upper case + ;; (setq up_string (format "%s%c" up_string key))) + ;; )) + ;; (current-case-table)) + ;; `map-char-table' was undefined. + (let ((key 0)) + (while (< key 256) + (cond + ((and + (eq (int-to-char key) (downcase key)) + (eq (int-to-char key) (upcase key))) + ;; Do nothing if upper and lower case are the same + ) + ((eq (int-to-char key) (downcase key)) + ;; The char is lower case + (setq low_string (format "%s%c" low_string key))) + ((eq (int-to-char key) (upcase key)) + ;; The char is upper case + (setq up_string (format "%s%c" up_string key))) + ) + (setq key (1+ key)))) + ;; ) + ;; The strings are single-byte strings + (setq prolog-upper-case-string (prolog-dash-letters up_string)) + (setq prolog-lower-case-string (prolog-dash-letters low_string)) + )) + +;(defun prolog-regexp-dash-continuous-chars (chars) +; (let ((ints (mapcar #'char-to-int (string-to-list chars))) +; (beg 0) +; (end 0)) +; (if (null ints) +; chars +; (while (and (< (+ beg 1) (length chars)) +; (not (or (= (+ (nth beg ints) 1) (nth (+ beg 1) ints)) +; (= (nth beg ints) (nth (+ beg 1) ints))))) +; (setq beg (+ beg 1))) +; (setq beg (+ beg 1) +; end beg) +; (while (and (< (+ end 1) (length chars)) +; (or (= (+ (nth end ints) 1) (nth (+ end 1) ints)) +; (= (nth end ints) (nth (+ end 1) ints)))) +; (setq end (+ end 1))) +; (if (equal (substring chars end) "") +; (substring chars 0 beg) +; (concat (substring chars 0 beg) "-" +; (prolog-regexp-dash-continuous-chars (substring chars end)))) +; ))) + +(defun prolog-ints-intervals (ints) + "Return a list of intervals (from . to) covering INTS." + (when ints + (setq ints (sort ints '<)) + (let ((prev (car ints)) + (interval-start (car ints)) + intervals) + (while ints + (let ((next (car ints))) + (when (> next (1+ prev)) ; start of new interval + (setq intervals (cons (cons interval-start prev) intervals)) + (setq interval-start next)) + (setq prev next) + (setq ints (cdr ints)))) + (setq intervals (cons (cons interval-start prev) intervals)) + (reverse intervals)))) + +(defun prolog-dash-letters (string) + "Return a condensed regexp covering all letters in STRING." + (let ((intervals (prolog-ints-intervals (mapcar #'char-to-int + (string-to-list string)))) + codes) + (while intervals + (let* ((i (car intervals)) + (from (car i)) + (to (cdr i)) + (c (cond ((= from to) `(,from)) + ((= (1+ from) to) `(,from ,to)) + (t `(,from ?- ,to))))) + (setq codes (cons c codes))) + (setq intervals (cdr intervals))) + (apply 'concat (reverse codes)))) + +;(defun prolog-condense-character-sets (regexp) +; "Condense adjacent characters in character sets of REGEXP." +; (let ((next -1)) +; (while (setq next (string-match "\\[\\(.*?\\)\\]" regexp (1+ next))) +; (setq regexp (replace-match (prolog-dash-letters (match-string 1 regexp)) +; t t regexp 1)))) +; regexp) + +;; GNU Emacs compatibility: GNU Emacs does not differentiate between +;; ints and chars, or at least these two are interchangeable. +(or (fboundp 'int-to-char) + ;; Introduced in Emacs 19.29. + (defun int-to-char (num) + num)) + +(or (fboundp 'char-to-int) + ;; Introduced in Emacs 19.29. + (defun char-to-int (num) + num)) + + +;;------------------------------------------------------------------- +;; Menu stuff (both for the editing buffer and for the inferior +;; prolog buffer) +;;------------------------------------------------------------------- + +(unless (fboundp 'region-exists-p) + (defun region-exists-p () + "Non-nil iff the mark is set. Lobotomized version for Emacsen that do not provide their own." + (mark))) + +(defun prolog-menu () + "Creates the menus for the Prolog editing buffers. +These menus are dynamically created because one may change systems +during the life of an Emacs session, and because GNU Emacs wants them +so by ignoring `easy-menu-add'." + + ;; GNU Emacs ignores `easy-menu-add' so the order in which the menus + ;; are defined _is_ important! + + (easy-menu-define + prolog-edit-menu-help (current-local-map) + "Help menu for the Prolog mode." + (append + (if (eq prolog-emacs 'xemacs) '("Help") '("Prolog-help")) + (cond + ((eq prolog-system 'sicstus) + '(["On predicate" prolog-help-on-predicate t] + "---")) + ((eq prolog-system 'swi) + '(["On predicate" prolog-help-on-predicate t] + ["Apropos" prolog-help-apropos t] + "---"))) + '(["Describe mode" describe-mode t]))) + + (easy-menu-define + prolog-edit-menu-runtime (current-local-map) + "Runtime Prolog commands available from the editing buffer" + (append + ;; runtime menu name + (list (cond ((eq prolog-system 'eclipse) + "ECLiPSe") + ((eq prolog-system 'mercury) + "Mercury") + (t + "Prolog"))) + ;; consult items, NIL for mercury + (unless (eq prolog-system 'mercury) + '("---" + ["Consult file" prolog-consult-file t] + ["Consult buffer" prolog-consult-buffer t] + ["Consult region" prolog-consult-region (region-exists-p)] + ["Consult predicate" prolog-consult-predicate t] + )) + ;; compile items, NIL for everything but SICSTUS + (when (eq prolog-system 'sicstus) + '("---" + ["Compile file" prolog-compile-file t] + ["Compile buffer" prolog-compile-buffer t] + ["Compile region" prolog-compile-region (region-exists-p)] + ["Compile predicate" prolog-compile-predicate t] + )) + ;; debug items, NIL for mercury + (cond + ((eq prolog-system 'sicstus) + ;; In SICStus, these are pairwise disjunctive, + ;; so it's enough with one "off"-command + (if (prolog-atleast-version '(3 . 7)) + (list "---" + ["Debug" prolog-debug-on t] + ["Trace" prolog-trace-on t] + ["Zip" prolog-zip-on t] + ["All debug off" prolog-debug-off t] + '("Source level debugging" + ["Enable" prolog-enable-sicstus-sd t] + ["Disable" prolog-disable-sicstus-sd t])) + (list "---" + ["Debug" prolog-debug-on t] + ["Trace" prolog-trace-on t] + ["All debug off" prolog-debug-off t]))) + ((not (eq prolog-system 'mercury)) + '("---" + ["Debug" prolog-debug-on t] + ["Debug off" prolog-debug-off t] + ["Trace" prolog-trace-on t] + ["Trace off" prolog-trace-off t])) + ;; default (mercury) nil + ) + (list "---" + (if (eq prolog-emacs 'xemacs) + [(concat "Run " (cond ((eq prolog-system 'eclipse) "ECLiPSe") + ((eq prolog-system 'mercury) "Mercury") + (t "Prolog"))) + run-prolog t] + ["Run Prolog" run-prolog t])))) + + (easy-menu-define + prolog-edit-menu-insert-move (current-local-map) + "Commands for Prolog code manipulation." + (append + (list "Code" + ["Comment region" comment-region (region-exists-p)] + ["Uncomment region" prolog-uncomment-region (region-exists-p)] + ["Add comment/move to comment" indent-for-comment t]) + (unless (eq prolog-system 'mercury) + (list ["Convert variables in region to '_'" prolog-variables-to-anonymous (region-exists-p)])) + (list "---" + ["Insert predicate template" prolog-insert-predicate-template t] + ["Insert next clause head" prolog-insert-next-clause t] + ["Insert predicate spec" prolog-insert-predspec t] + ["Insert module modeline" prolog-insert-module-modeline t] + "---" + ["Beginning of clause" prolog-beginning-of-clause t] + ["End of clause" prolog-end-of-clause t] + ["Beginning of predicate" prolog-beginning-of-predicate t] + ["End of predicate" prolog-end-of-predicate t] + "---" + ["Indent line" prolog-indent-line t] + ["Indent region" indent-region (region-exists-p)] + ["Indent predicate" prolog-indent-predicate t] + ["Indent buffer" prolog-indent-buffer t] + ["Align region" align (region-exists-p)] + "---" + ["Mark clause" prolog-mark-clause t] + ["Mark predicate" prolog-mark-predicate t] + ["Mark paragraph" mark-paragraph t] + ;"---" + ;["Fontify buffer" font-lock-fontify-buffer t] + ))) + + (easy-menu-add prolog-edit-menu-insert-move) + (easy-menu-add prolog-edit-menu-runtime) + + ;; Add predicate index menu + ;(make-variable-buffer-local 'imenu-create-index-function) + (make-local-variable 'imenu-create-index-function) + (setq imenu-create-index-function 'imenu-default-create-index-function) + ;;Milan (this has problems with object methods...) ###### Does it? (Stefan) + (setq imenu-prev-index-position-function 'prolog-beginning-of-predicate) + (setq imenu-extract-index-name-function 'prolog-get-predspec) + + (if (and prolog-imenu-flag + (< (count-lines (point-min) (point-max)) prolog-imenu-max-lines)) + (imenu-add-to-menubar "Predicates")) + + (easy-menu-add prolog-edit-menu-help)) + +(defun prolog-inferior-menu () + "Creates the menus for the Prolog inferior buffer. +This menu is dynamically created because one may change systems during +the life of an Emacs session." + + (easy-menu-define + prolog-inferior-menu-help (current-local-map) + "Help menu for the Prolog inferior mode." + (append + (if (eq prolog-emacs 'xemacs) '("Help") '("Prolog-help")) + (cond + ((eq prolog-system 'sicstus) + '(["On predicate" prolog-help-on-predicate t] + "---")) + ((eq prolog-system 'swi) + '(["On predicate" prolog-help-on-predicate t] + ["Apropos" prolog-help-apropos t] + "---"))) + '(["Describe mode" describe-mode t]))) + + (easy-menu-define + prolog-inferior-menu-all (current-local-map) + "Menu for the inferior Prolog buffer." + (append + ;; menu name + (list (cond ((eq prolog-system 'eclipse) + "ECLiPSe") + ((eq prolog-system 'mercury) + "Mercury") + (t + "Prolog"))) + ;; debug items, NIL for mercury + (cond + ((eq prolog-system 'sicstus) + ;; In SICStus, these are pairwise disjunctive, + ;; so it's enough with one "off"-command + (if (prolog-atleast-version '(3 . 7)) + (list "---" + ["Debug" prolog-debug-on t] + ["Trace" prolog-trace-on t] + ["Zip" prolog-zip-on t] + ["All debug off" prolog-debug-off t] + '("Source level debugging" + ["Enable" prolog-enable-sicstus-sd t] + ["Disable" prolog-disable-sicstus-sd t])) + (list "---" + ["Debug" prolog-debug-on t] + ["Trace" prolog-trace-on t] + ["All debug off" prolog-debug-off t]))) + ((not (eq prolog-system 'mercury)) + '("---" + ["Debug" prolog-debug-on t] + ["Debug off" prolog-debug-off t] + ["Trace" prolog-trace-on t] + ["Trace off" prolog-trace-off t])) + ;; default (mercury) nil + ) + ;; runtime + '("---" + ["Interrupt Prolog" comint-interrupt-subjob t] + ["Quit Prolog" comint-quit-subjob t] + ["Kill Prolog" comint-kill-subjob t]) + )) + + (easy-menu-add prolog-inferior-menu-all) + (easy-menu-add prolog-inferior-menu-help)) + +(add-hook 'prolog-mode-hook 'prolog-menu) +(add-hook 'prolog-inferior-mode-hook 'prolog-inferior-menu) + +(add-hook 'prolog-mode-hook '(lambda () (font-lock-mode 1))) +(add-hook 'prolog-inferior-mode-hook '(lambda () (font-lock-mode 1))) + + +(defun prolog-mode-version () + "Echo the current version of Prolog mode in the minibuffer." + (interactive) + (message "Using Prolog mode version %s" prolog-mode-version)) + +(provide 'prolog) + +;;; prolog.el ends here diff --git a/lisp/python-environment.el b/lisp/python-environment.el new file mode 100644 index 0000000..f2e4afe --- /dev/null +++ b/lisp/python-environment.el @@ -0,0 +1,246 @@ +;;; python-environment.el --- virtualenv API for Emacs Lisp + +;; Copyright (C) 2013 Takafumi Arakaki + +;; Author: Takafumi Arakaki +;; Keywords: applications, tools +;; Version: 0.0.2alpha0 +;; Package-Requires: ((deferred "0.3.1")) + +;; This file is NOT part of GNU Emacs. + +;; python-environment.el 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. + +;; python-environment.el 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 python-environment.el. +;; If not, see . + +;;; Commentary: + +;; + +;;; Code: + +(eval-when-compile (require 'cl)) +(require 'deferred) + +(defconst python-environment-version "0.0.2alpha0") + +(defcustom python-environment-directory + (locate-user-emacs-file ".python-environments") + "Path to directory to store all Python virtual environments. A string. + +If you want to change the location to, say ``~/.python-environments``, +then set it like this in your Emacs setup file:: + + (setq python-environment-directory \"~/.python-environments\")" + :group 'python-environment) + +(defcustom python-environment-default-root-name "default" + "Default Python virtual environment name. A string. + +This is a name of directory relative to `python-environment-directory' +where default virtual environment locates. +Thus, typically the default virtual environment path is +``~/.emacs.d/.python-environments/default``." + :group 'python-environment) + +(defcustom python-environment-virtualenv + (list "virtualenv" "--system-site-packages" "--quiet") + ;; --quiet is required for Windows. Without it, virtualenv raises + ;; UnicodeEncodeError + ;; See: https://github.com/tkf/emacs-jedi/issues/148#issuecomment-38290546 + "``virtualenv`` command to use, including command options. List of strings. + +For example, if you want to use specific Python executable (to +specify Python version), append ``--python`` option like this:: + + (setq python-environment-virtualenv + (append python-environment-virtualenv + '(\"--python\" \"PATH/TO/bin/python\"))) + +I added ``--system-site-packages`` as default, but this is not +mandatory. If you don't like it, removing does not break +anything (well, theoretically). For reason why it is default, +see discussion here: +https://github.com/tkf/emacs-python-environment/issues/3" + :group 'python-environment) + +(defvar python-environment--verbose nil) + +(defun python-environment--deferred-process (msg command) + (message "%s..." msg) + (deferred:$ + (apply #'deferred:process command) + (deferred:watch it + (apply-partially + (lambda (msg output) + (message "%s...Done" msg) + (when python-environment--verbose + (message output))) + msg)))) + +(defun python-environment--blocking-process (msg command) + (message "%s (SYNC)..." msg) + (let (exit-code output) + (with-temp-buffer + (setq exit-code + (apply #'call-process (car command) + nil ; INFILE (no input) + t ; BUFFER (output to this buffer) + nil ; DISPLAY (no refresh is needed) + (cdr command))) + (setq output (buffer-string))) + (when (or python-environment--verbose + (not (= exit-code 0))) + (message output)) + (message "%s (SYNC)...Done" msg) + (unless (= exit-code 0) + (error "Command %S exits with error code %S." command exit-code)))) + + +(defun python-environment-root-path (&optional root) + (expand-file-name (or root python-environment-default-root-name) + python-environment-directory)) + +(defun python-environment--make-with-runner (proc-runner root virtualenv) + (let ((path (convert-standard-filename + (python-environment-root-path root))) + (virtualenv (append (or virtualenv python-environment-virtualenv) + (when python-environment--verbose + (list "--verbose"))))) + (unless (executable-find (car virtualenv)) + (error "Program named %S does not exist." (car virtualenv))) + (funcall proc-runner + (format "Making virtualenv at %s" path) + (append virtualenv (list path))))) + +(defun python-environment-make (&optional root virtualenv) + "Make virtual environment at ROOT asynchronously. + +This function does not wait until ``virtualenv`` finishes. +Instead, it returns a deferred object [#]_. So, if you want to +do some operation after the ``virtualenv`` command finishes, do +something like this:: + + (deferred:$ + (python-environment-make) + (deferred:nextc it (lambda (output) DO-SOMETHING-HERE))) + +If ROOT is specified, it is used instead of +`python-environment-default-root-name'. ROOT can be a relative +path from `python-environment-virtualenv' or an absolute path. + +If VIRTUALENV (list of string) is specified, it is used instead of +`python-environment-virtualenv'. + +.. [#] https://github.com/kiwanami/emacs-deferred" + (python-environment--make-with-runner + #'python-environment--deferred-process + root virtualenv)) + +(defun python-environment-make-block (&optional root virtualenv) + "Blocking version of `python-environment-make'. +I recommend NOT to use this function in interactive commands. +For reason, see `python-environment-run-block'" + (python-environment--make-with-runner + #'python-environment--blocking-process + root virtualenv)) + +(defun python-environment-exists-p (&optional root) + "Return non-`nil' if virtualenv at ROOT exists. +See `python-environment-make' for how ROOT is interpreted." + (let ((bin (python-environment-bin "python" root))) + (and bin (file-exists-p bin)))) + +(defun python-environment--existing (root &rest paths) + (when paths + (let ((full-path (expand-file-name (car paths) + (python-environment-root-path root)))) + (if (file-exists-p full-path) + full-path + (apply #'python-environment--existing root (cdr paths)))))) + +(defun python-environment-bin (path &optional root) + "Return full path to \"ROOT/bin/PATH\" or \"ROOT/Scripts/PATH\" if exists. +``Scripts`` is used instead of ``bin`` in typical Windows case. +In Windows, path with extension \".ext\" may be returned. +See `python-environment-make' for how ROOT is interpreted." + (python-environment--existing root + (concat "bin/" path) + (concat "Scripts/" path) + (concat "Scripts/" path ".exe"))) + +(defun python-environment-lib (path &optional root) + "Return full path to \"ROOT/lib/PATH\" or \"ROOT/Lib/PATH\" if exists. +``Lib`` is used instead of ``lib`` in typical Windows case. +See `python-environment-make' for how ROOT is interpreted." + (python-environment--existing root + (concat "lib/" path) + (concat "Lib/" path))) + +(defun python-environment--run-with-runner (proc-runner command root) + (funcall proc-runner + (format "Running: %s" (mapconcat 'identity command " ")) + (cons (python-environment-bin (car command) root) + (cdr command)))) + +(defun python-environment--run-1 (&optional command root) + (python-environment--run-with-runner + #'python-environment--deferred-process + command root)) + +(defun python-environment--run-block-1 (command root) + (python-environment--run-with-runner + #'python-environment--blocking-process + command root)) + +(defun python-environment-run (command &optional root virtualenv) + "Run COMMAND installed in Python virtualenv located at ROOT +asynchronously. + +Instead of waiting for COMMAND to finish, a deferred object [#]_ +is returned so that you can chain operations. + +See `python-environment-make' for how ROOT and VIRTUALENV are +interpreted and how to work with deferred object. + +Use `python-environment-run-block' if you want to wait until +the command exit (NOT recommended in interactive command). + +.. [#] https://github.com/kiwanami/emacs-deferred" + (if (python-environment-exists-p root) + (python-environment--run-1 command root) + (deferred:$ + (python-environment-make root virtualenv) + (deferred:nextc it + (apply-partially + (lambda (command root _) + (python-environment--run-1 command root)) + command root))))) + +(defun python-environment-run-block (command &optional root virtualenv) + "Blocking version of `python-environment-run'. +I recommend NOT to use this function in interactive commands. +Emacs users have more important things to than waiting for some +command to finish." + (unless (python-environment-exists-p root) + (python-environment-make-block root virtualenv)) + (python-environment--run-block-1 command root)) + +(provide 'python-environment) + +;; Local Variables: +;; coding: utf-8 +;; indent-tabs-mode: nil +;; End: + +;;; python-environment.el ends here diff --git a/lisp/recentf.el b/lisp/recentf.el new file mode 100644 index 0000000..9f6f928 --- /dev/null +++ b/lisp/recentf.el @@ -0,0 +1,1380 @@ +;; recentf.el --- setup a menu of recently opened files + +;; Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + +;; Author: David Ponce +;; Created: July 19 1999 +;; Keywords: customization + +;; 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 2, 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; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This package maintains a menu for visiting files that were operated +;; on recently. When enabled a new "Open Recent" submenu is displayed +;; in the "Files" menu. The recent files list is automatically saved +;; across Emacs sessions. You can customize the number of recent +;; files displayed, the location of the menu and others options (see +;; the source code for details). To install and use, put the file on +;; your Emacs-Lisp load path and add the following into your ~/.emacs +;; startup file: +;; +;; (require 'recentf) +;; (recentf-mode 1) + +;;; History: +;; + +;;; Code: + +;;; Compatibility +(if (featurep 'xemacs) + (progn + (defalias 'recentf-overlay-lists + (lambda () (list (extent-list)))) + (defalias 'recentf-delete-overlay 'delete-extent) + ) + (defalias 'recentf-overlay-lists 'overlay-lists) + (defalias 'recentf-delete-overlay 'delete-overlay) + ) + +;; Canonicalize file names so the same list of recently opened files +;; could be shared between various versions of Emacs and XEmacs. +(defun recentf-expand-file-name (name &optional dir) + "Convert filename NAME to absolute, and canonicalize it. +Second arg DIR is directory to start with if NAME is relative (see +function `expand-file-name'). Also, force directory separator +character (see variable `directory-sep-char') to ?/." + (let ((directory-sep-char ?/)) + (expand-file-name name))) + +(require 'easymenu) +(require 'wid-edit) + +(defconst recentf-save-file-header + ";;; Automatically generated by `recentf' on %s.\n" + "Header to be written into the `recentf-save-file'.") + +(defvar recentf-list nil + "List of recently opened files.") + +(defvar recentf-update-menu-p t + "Non-nil if the recentf menu must be updated.") + +(defvar recentf-initialized-p nil + "Non-nil if recentf already initialized.") + +;; IMPORTANT: This function must be defined before the following defcustoms +;; because it is used in their :set clause. To avoid byte-compiler warnings +;; the `symbol-value' function is used to access the `recentf-menu-path' +;; and `recentf-menu-title' values. +(defun recentf-menu-customization-changed (sym val) + "Function called when menu customization has changed. +It removes the recentf menu and forces its complete redrawing. SYM is +the variable customized and VAL its new value." + (when recentf-initialized-p + (easy-menu-remove-item nil + (symbol-value 'recentf-menu-path) + (symbol-value 'recentf-menu-title)) + (setq recentf-update-menu-p t)) + (set-default sym val)) + +(defgroup recentf nil + "Maintain a menu of recently opened files." + :version "21.1" + :group 'files) + +(defgroup recentf-filters nil + "Group to customize recentf menu filters. +You should define the options of your own filters in this group." + :group 'recentf) + +(defcustom recentf-max-saved-items 20 + "*Maximum number of items saved to `recentf-save-file'." + :group 'recentf + :type 'integer) + +(defcustom recentf-save-file (recentf-expand-file-name "~/.recentf") + "*File to save `recentf-list' into." + :group 'recentf + :type 'file) + +(defcustom recentf-exclude nil + "*List of regexps for filenames excluded from `recentf-list'." + :group 'recentf + :type '(repeat regexp)) + +(defcustom recentf-menu-title "Open Recent" + "*Name of the recentf menu." + :group 'recentf + :type 'string + :set 'recentf-menu-customization-changed) + +(defcustom recentf-menu-path (if (featurep 'xemacs) + '("File") + '("files")) + "*Path where to add the recentf menu. +If nil add it at top level (see also `easy-menu-change')." + :group 'recentf + :type '(choice (const :tag "Top Level" nil) + (sexp :tag "Menu Path")) + :set 'recentf-menu-customization-changed) + +(defcustom recentf-menu-before (if (featurep 'xemacs) + "Open..." + "open-file") + "*Name of the menu before which the recentf menu will be added. +If nil add it at end of menu (see also `easy-menu-change')." + :group 'recentf + :type '(choice (string :tag "Name") + (const :tag "Last" nil)) + :set 'recentf-menu-customization-changed) + +(defcustom recentf-menu-action 'recentf-find-file + "*Function to invoke with a filename item of the recentf menu. +The default action `recentf-find-file' calls `find-file' to edit an +existing file. If the file does not exist or is not readable, it is +not edited and its name is removed from `recentf-list'. You can use +`find-file' instead to open non-existing files and keep them in the +list of recently opened files." + :group 'recentf + :type 'function + :set 'recentf-menu-customization-changed) + +(defcustom recentf-max-menu-items 10 + "*Maximum number of items in the recentf menu." + :group 'recentf + :type 'integer + :set 'recentf-menu-customization-changed) + +(defcustom recentf-menu-filter nil + "*Function used to filter files displayed in the recentf menu. +Nil means no filter. The following functions are predefined: + +- `recentf-sort-ascending' to sort menu items in ascending order. +- `recentf-sort-descending' to sort menu items in descending order. +- `recentf-sort-basenames-ascending' to sort file names in descending order. +- `recentf-sort-basenames-descending' to sort file names in descending order. +- `recentf-sort-directories-ascending' to sort directories in ascending order. +- `recentf-sort-directories-descending' to sort directories in descending order. +- `recentf-show-basenames' to show file names (no directories) in menu items. +- `recentf-show-basenames-ascending' to show file names in ascending order. +- `recentf-show-basenames-descending' to show file names in descending order. +- `recentf-relative-filter' to show file names relative to `default-directory'. +- `recentf-arrange-by-rule' to show sub-menus following user defined rules. +- `recentf-arrange-by-mode' to show a sub-menu for each major mode. +- `recentf-arrange-by-dir' to show a sub-menu for each directory. +- `recentf-filter-changer' to manage a ring of filters. + +The filter function is called with one argument, the list of menu elements +used to build the menu and must return a new list of menu elements (see +`recentf-make-menu-element' for menu element form)." + :group 'recentf + :type '(radio (const nil) + (function-item recentf-sort-ascending) + (function-item recentf-sort-descending) + (function-item recentf-sort-basenames-ascending) + (function-item recentf-sort-basenames-descending) + (function-item recentf-sort-directories-ascending) + (function-item recentf-sort-directories-descending) + (function-item recentf-show-basenames) + (function-item recentf-show-basenames-ascending) + (function-item recentf-show-basenames-descending) + (function-item recentf-relative-filter) + (function-item recentf-arrange-by-rule) + (function-item recentf-arrange-by-mode) + (function-item recentf-arrange-by-dir) + (function-item recentf-filter-changer) + function) + :set 'recentf-menu-customization-changed) + +(defcustom recentf-menu-append-commands-p t + "*If not-nil command items are appended to the menu." + :group 'recentf + :type 'boolean + :set 'recentf-menu-customization-changed) + +(defcustom recentf-keep-non-readable-files-p nil + "*If nil (default), non-readable files are not kept in `recentf-list'." + :group 'recentf + :type 'boolean + :require 'recentf + :initialize 'custom-initialize-default + :set (lambda (sym val) + (if val + (remove-hook 'kill-buffer-hook 'recentf-remove-file-hook) + (add-hook 'kill-buffer-hook 'recentf-remove-file-hook)) + (set-default sym val))) + +(defcustom recentf-virtual-pathes-handler + (if (eq system-type 'windows-nt) + #'recentf-windows-nt-virtual-drives + nil) + "*Handler of virtual pathes. +This is a function without argument which must return an alist of: + + (VIRTUAL-PATH . REAL-PATH). + +See also the variable `recentf-virtual-pathes-alist'." + :group 'recentf + :type 'function) + +(defcustom recentf-link-behavior 'always-link-source + "*Define how recentf should handle filenames which are links. +That is for which maybe an entry with only another name exists in the +recent file list. There are three choices: + +- - 'always-link-source': always save the `recentf-file-truename', + means the name of the link-source, in the `recentf-list'. +- - 'only-one-version': if the file is already saved in the + `recentf-list' with another name then nothing is done. +- - nil: there is no special link handling and a file can be saved + with different names in the `recentf-list'. + +See also `recentf-rebuild-virtual-pathes'." + :group 'recentf + :type '(radio (const :tag "Save link source" + :value always-link-source) + (const :tag "Save only one name" + :value only-one-version) + (const :tag "No special link handling" + :value nil))) + +(defcustom recentf-mode nil + "Toggle recentf mode. +When recentf mode is enabled, it maintains a menu for visiting files that +were operated on recently. +Setting this variable directly does not take effect; +use either \\[customize] or the function `recentf-mode'." + :set (lambda (symbol value) + (recentf-mode (or value 0))) + :initialize 'custom-initialize-default + :type 'boolean + :group 'recentf + :require 'recentf) + +(defcustom recentf-load-hook nil + "*Normal hook run at end of loading the `recentf' package." + :group 'recentf + :type 'hook) + +(defvar recentf-auto-cleanup-timer nil + "Timer used to automatically cleanup the `recentf-list'. +See also the `recentf-auto-cleanup' option.") + +(defcustom recentf-auto-cleanup 'enable + "*Define how to automatically cleanup the `recentf-list'. + +The following values are recognized: + +- 'enable: cleanup when turning recentf mode on (default). +- NUMBER: cleanup each time Emacs has been idle for NUMBER seconds. +- TIME: cleanup at TIME where TIME must be a string like \"11:30pm\". +- 'never: disable automatic cleanup. + +You can always perform a manual cleanup of the `recentf-list' with +\\[recentf-cleanup]. + +Do not change this variable directly but always use customize!" + :group 'recentf + :type '(radio + (const :tag "When mode enabled" + :value enable) + (const :tag "Never" + :value never) + (number :tag "After idle seconds" + :value 300) + (string :tag "At time" + :value "11:00pm") + ) + :set (lambda (symbol value) + (set symbol value) + (when recentf-mode + ;; Always cancel any existing timer + (recentf-cancel-cleanup-timer) + (cond + ((numberp recentf-auto-cleanup) + (setq recentf-auto-cleanup-timer + (run-with-idle-timer recentf-auto-cleanup + t + 'recentf-cleanup)) + ) + ((stringp recentf-auto-cleanup) + (setq recentf-auto-cleanup-timer + (run-at-time recentf-auto-cleanup + nil + 'recentf-cleanup)) + ))))) + +;;;; +;;;; Common functions +;;;; + +(defun recentf-cancel-cleanup-timer () + "Cancel the auto cleanup timer." + (if (timerp recentf-auto-cleanup-timer) + (cancel-timer recentf-auto-cleanup-timer)) + (setq recentf-auto-cleanup-timer nil)) + +(defconst recentf-case-fold-search + (memq system-type '(vax-vms windows-nt)) + "Non-nil if recentf searches and matches should ignore case.") + +(defun recentf-string-equal (s1 s2) + "Return non-nil if strings S1 and S2 have identical contents. +Ignore case if `recentf-case-fold-search' is non-nil." + (if recentf-case-fold-search + (string-equal (downcase s1) (downcase s2)) + (string-equal s1 s2))) + +(defun recentf-string-lessp (s1 s2) + "Return non-nil if string S1 is less than S2 in lexicographic order. +Ignore case if `recentf-case-fold-search' is non-nil." + (if recentf-case-fold-search + (string-lessp (downcase s1) (downcase s2)) + (string-lessp s1 s2))) + +(defun recentf-string-member (elt list) + "Return non-nil if string ELT is an element of LIST. +LIST is a list of strings. The value is actually the tail of LIST +whose car is ELT. Ignore case if `recentf-case-fold-search' is +non-nil." + (if recentf-case-fold-search + (setq elt (downcase elt))) + (while (and list + (not (string-equal elt (if recentf-case-fold-search + (downcase (car list)) + (car list))))) + (setq list (cdr list))) + list) + +(defun recentf-push (path) + "Push PATH into the `recentf-list'. +That is move or add PATH at the beginning of `recentf-list'. Also, +ignore case when comparing pathes if `recentf-case-fold-search' is +non-nil." + (let ((elt (if recentf-case-fold-search + (downcase path) + path)) + nl) + (while recentf-list + (or (string-equal elt (if recentf-case-fold-search + (downcase (car recentf-list)) + (car recentf-list))) + (setq nl (cons (car recentf-list) nl))) + (setq recentf-list (cdr recentf-list))) + (setq recentf-list (cons path (nreverse nl))))) + +(defun recentf-windows-nt-virtual-drives () + "Return an alist of Windows NT virtual drive associations. +This is the default `recentf-virtual-pathes-handler' when +`system-type' is 'windows-nt. Run \\[recentf-rebuild-virtual-pathes] +if you are adding/changing/removing virtual drives with the \"subst\" +command during Emacs session!" + (if (eq system-type 'windows-nt) + (let ((directory-sep-char ?/)) + (mapcar + #'(lambda (line) + (let ((vdrive (split-string line ": +=> +"))) + (cons + (file-name-as-directory + (expand-file-name (nth 0 vdrive))) + (file-name-as-directory + (expand-file-name (nth 1 vdrive)))))) + (delete "" ;; XEmacs `split-string' can return empty lines so + ;; remove them! + (split-string + ;; Force use of the Windows NT built-in shell + ;; because some people may have setup other + ;; `shell-file-name' like bash. Also, on XEmacs + ;; 21.4, `directory-sep-char' value must be ?\\ to + ;; successfully execute Windows NT shell commands! + (let ((shell-file-name (getenv "ComSpec")) + (shell-command-switch "/c") + (directory-sep-char ?\\)) + (shell-command-to-string "subst")) + "[\n]+")))))) + +(defvar recentf-virtual-pathes-alist nil + "Hold the alist of virtual pathes associations. +Each association has the form: + + ( ).") + +;;;###autoload +(defun recentf-rebuild-virtual-pathes () + "Rebuild the list of virtual pathes. +The list is kept in variable `recentf-virtual-pathes-alist' so the +substituted pathes can be handled correctly by recentf. See also the +variable `recentf-link-behavior'." + (interactive) + (setq recentf-virtual-pathes-alist + (and (functionp recentf-virtual-pathes-handler) + (funcall recentf-virtual-pathes-handler)))) + +(defun recentf-file-truename (filename) + "Return the real file name of FILENAME. +If `recentf-virtual-pathes-alist' is non-nil substitute a virtual path +found in FILENAME by the corresponding real path in +`recentf-virtual-pathes-alist'. Otherwise just return the +`file-truename' of FILENAME." + (let* ((case-fold-search recentf-case-fold-search) + (directory-sep-char ?/) + (truename (expand-file-name + (file-truename filename))) + (vpathes recentf-virtual-pathes-alist) + found vpath) + (while (and (not found) vpathes) + (setq vpath (car vpathes) + vpathes (cdr vpathes)) + (if (string-match (concat "^" (regexp-quote (car vpath))) + truename) + (setq truename (replace-match (cdr vpath) nil nil + truename) + found t))) + truename)) + +(defun recentf-include-p (filename) + "Return t if FILENAME match none of the `recentf-exclude' regexps." + (let ((case-fold-search recentf-case-fold-search) + (rl recentf-exclude)) + (while (and rl (not (string-match (car rl) filename))) + (setq rl (cdr rl))) + (null rl))) + +(defun recentf-add-file (filename) + "Add or move FILENAME at the beginning of `recentf-list'. +Does nothing if FILENAME matches one of the `recentf-exclude' regexps. +The behavior depends on `recentf-link-behavior'." + (let* ((filename (recentf-expand-file-name filename)) + (true-filename (recentf-file-truename filename)) + r-list found) + (when (recentf-include-p filename) + (cond + ;; Add the FILENAME to the list, but ensure there is no other + ;; "identical" files in the list with different names. + ((eq recentf-link-behavior 'only-one-version) + (setq r-list (copy-sequence recentf-list)) + (while (and (not found) r-list) + (setq found (recentf-string-equal + (recentf-file-truename (car r-list)) + true-filename) + r-list (cdr r-list))) + ;; There is no "identical" file in the `recentf-list' so we + ;; must add it now. + (or found (recentf-push filename))) + + ;; Add the `recentf-file-truename' to the list, so we never + ;; have a file twice in the list with different names. + ((eq recentf-link-behavior 'always-link-source) + (recentf-push true-filename)) + + ;; Simply add or move the file at the beginning. + (t + (recentf-push filename))) + (setq recentf-update-menu-p t)))) + +(defun recentf-remove-if-non-readable (filename) + "Remove FILENAME from `recentf-list' if not readable." + (unless (file-readable-p filename) + (recentf-push filename) + (setq recentf-list (cdr recentf-list)) + (setq recentf-update-menu-p t))) + +(defun recentf-find-file (filename) + "Edit file FILENAME using `find-file'. +If FILENAME is not readable it is removed from `recentf-list'." + (if (file-readable-p filename) + (find-file filename) + (progn + (message "File `%s' not found." filename) + (recentf-remove-if-non-readable filename)))) + +(defun recentf-trunc-list (l n) + "Return from L the list of its first N elements." + (let ((lh nil)) + (while (and l (> n 0)) + (setq lh (cons (car l) lh)) + (setq n (1- n)) + (setq l (cdr l))) + (nreverse lh))) + +(defun recentf-elements (n) + "Return a list of the first N elements of `recentf-list'." + (recentf-trunc-list recentf-list n)) + +(defun recentf-make-menu-element (menu-item menu-value) + "Create a new menu-element. + +A menu element is a pair (MENU-ITEM . MENU-VALUE) where: + +- - MENU-ITEM is the menu item string displayed. +- - MENU-VALUE is the path used to open the file when the + corresponding MENU-ITEM is selected. Or it is + a pair (SUB-MENU-TITLE . MENU-ELEMENTS) where + SUB-MENU-TITLE is a sub-menu title and + MENU-ELEMENTS is the list of menu elements in + the sub-menu." + (cons menu-item menu-value)) + +(defun recentf-menu-element-item (e) + "Return the item part of the menu-element E." + (car e)) + +(defun recentf-menu-element-value (e) + "Return the value part of the menu-element E." + (cdr e)) + +(defun recentf-set-menu-element-item (e item) + "Change the item part of menu-element E to ITEM." + (setcar e item)) + +(defun recentf-set-menu-element-value (e value) + "Change the value part of menu-element E to VALUE." + (setcdr e value)) + +(defun recentf-sub-menu-element-p (e) + "Return non-nil if menu-element E defines a sub-menu." + (consp (recentf-menu-element-value e))) + +(defun recentf-make-default-menu-element (file-path) + "Make a new default menu element (MENU-ITEM . MENU-VALUE). +Do so for the given recent file path FILE-PATH. MENU-ITEM and +MENU-VALUE are set to FILE-PATH. See also +`recentf-make-menu-element'." + (recentf-make-menu-element file-path file-path)) + +(defun recentf-menu-elements (n) + "Return a list of the first N default menu elements from `recentf-list'. +See also `recentf-make-default-menu-element'." + (mapcar 'recentf-make-default-menu-element + (recentf-elements n))) + +(defun recentf-apply-menu-filter (filter l) + "Apply function FILTER to the list of menu-elements L. +It takes care of sub-menu elements in L and recursively apply FILTER +to them. It is guaranteed that FILTER receives only a list of single +menu-elements (no sub-menu)." + (if (and (functionp filter) l) + (let ((case-fold-search recentf-case-fold-search) + (directory-sep-char ?/) + menu-element sub-menu-elements single-elements) + ;; split L in two sub-listes: + ;; one of sub-menus elements and + ;; one of single menu elements + (while l + (setq menu-element (car l)) + (if (recentf-sub-menu-element-p menu-element) + (setq sub-menu-elements + (cons menu-element sub-menu-elements)) + (setq single-elements + (cons menu-element single-elements))) + (setq l (cdr l))) + ;; apply FILTER to the list of single menu elements + (if single-elements + (setq single-elements (funcall filter + (nreverse single-elements)))) + ;; apply FILTER to sub-menu menu element list + (setq l sub-menu-elements) + (setq sub-menu-elements nil) + (while l + (setq menu-element (car l)) + (recentf-set-menu-element-value + menu-element + (recentf-apply-menu-filter + filter + (recentf-menu-element-value menu-element))) + (setq sub-menu-elements (cons menu-element sub-menu-elements)) + (setq l (cdr l))) + ;; build and return the new filtered menu element list + (nconc sub-menu-elements single-elements)) + l)) + +(defvar recentf-menu-items-for-commands + (list ["Cleanup list" recentf-cleanup t] + ["Edit list..." recentf-edit-list t] + ["Save list now" recentf-save-list t] + (vector "Recentf Options..." '(customize-group "recentf") t)) + "List of menu items for recentf commands.") + +(defvar recentf-menu-filter-commands nil + "This variable can be used by menu filters to setup their own command menu. + +If non-nil it must contain a list of valid menu-items to be appended +to the recent file list part of the menu. Before calling a menu +filter function this variable is reset to nil.") + +(defun recentf-make-menu-items () + "Make menu items from `recentf-list'." + (setq recentf-menu-filter-commands nil) + (let ((file-items + (mapcar 'recentf-make-menu-item + (recentf-apply-menu-filter + recentf-menu-filter + (recentf-menu-elements recentf-max-menu-items))))) + (append (or file-items (list ["No files" t nil])) + (and (< recentf-max-menu-items (length recentf-list)) + (list ["More..." recentf-open-more-files t])) + (and recentf-menu-filter-commands + (cons "---" + recentf-menu-filter-commands)) + (and recentf-menu-append-commands-p + (cons "---" + recentf-menu-items-for-commands))))) + +(defun recentf-make-menu-item (menu-element) + "Make a menu item from MENU-ELEMENT (see `recentf-make-menu-element')." + (let ((menu-item (recentf-menu-element-item menu-element)) + (menu-value (recentf-menu-element-value menu-element))) + (if (recentf-sub-menu-element-p menu-element) + (cons menu-item (mapcar 'recentf-make-menu-item menu-value)) + (vector menu-item + (list recentf-menu-action menu-value) + t)))) + +;;;; +;;;; Predefined menu filter functions +;;;; + +(defun recentf-sort-ascending (l) + "Sort the list of menu elements L in ascending order. +The MENU-ITEM part of each menu element is compared." + (sort (copy-sequence l) + (function + (lambda (e1 e2) + (recentf-string-lessp + (recentf-menu-element-item e1) + (recentf-menu-element-item e2)))))) + +(defun recentf-sort-descending (l) + "Sort the list of menu elements L in descending order. +The MENU-ITEM part of each menu element is compared." + (sort (copy-sequence l) + (function + (lambda (e1 e2) + (recentf-string-lessp + (recentf-menu-element-item e2) + (recentf-menu-element-item e1)))))) + +(defun recentf-sort-basenames-ascending (l) + "Sort the list of menu elements L in ascending order. +Only file names (without directories) are compared." + (sort (copy-sequence l) + (function + (lambda (e1 e2) + (recentf-string-lessp + (file-name-nondirectory (recentf-menu-element-value e1)) + (file-name-nondirectory (recentf-menu-element-value e2))))))) + +(defun recentf-sort-basenames-descending (l) + "Sort the list of menu elements L in descending order. +Only file names (without directories) are compared." + (sort (copy-sequence l) + (function + (lambda (e1 e2) + (recentf-string-lessp + (file-name-nondirectory (recentf-menu-element-value e2)) + (file-name-nondirectory (recentf-menu-element-value e1))))))) + +(defun recentf-directory-compare (p1 p2) + "Compare directories then filenames in paths P1 and P2. +Return non-nil if P1 is less than P2." + (let ((d1 (file-name-directory p1)) + (f1 (file-name-nondirectory p1)) + (d2 (file-name-directory p2)) + (f2 (file-name-nondirectory p2))) + (if (recentf-string-equal d1 d2) + (recentf-string-lessp f1 f2) + (recentf-string-lessp d1 d2)))) + +(defun recentf-sort-directories-ascending (l) + "Sort the list of menu elements L in ascending order. +Compares directories then filenames to order the list." + (sort (copy-sequence l) + (function + (lambda (e1 e2) + (recentf-directory-compare (recentf-menu-element-value e1) + (recentf-menu-element-value e2)))))) + +(defun recentf-sort-directories-descending (l) + "Sort the list of menu elements L in descending order. +Compares directories then filenames to order the list." + (sort (copy-sequence l) + (function + (lambda (e1 e2) + (recentf-directory-compare (recentf-menu-element-value e2) + (recentf-menu-element-value e1)))))) + +(defun recentf-show-basenames (l) + "Filter the list of menu elements L to show only file names (no directories) +in the menu. When file names are duplicated their directory component is added." + (let ((names (mapcar (function + (lambda (item) + (file-name-nondirectory + (recentf-menu-element-value item)))) + l)) + (dirs (mapcar (function + (lambda (item) + (file-name-directory + (recentf-menu-element-value item)))) + l)) + (pathes (mapcar 'recentf-menu-element-value l)) + (pos -1) + item filtered-items filtered-list) + (while names + (setq item (car names)) + (setq names (cdr names)) + (setq pos (1+ pos)) + (setq filtered-list + (cons (recentf-make-menu-element + (if (or (recentf-string-member item names) + (recentf-string-member item filtered-items)) + (concat item " (" (nth pos dirs) ")") + item) + (nth pos pathes)) + filtered-list)) + (setq filtered-items (cons item filtered-items))) + (nreverse filtered-list))) + +(defun recentf-show-basenames-ascending (l) + "Filter the list of menu elements L. +Show only file names in the menu, sorted in ascending order. This +filter combines the `recentf-sort-basenames-ascending' and +`recentf-show-basenames' filters." + (recentf-show-basenames (recentf-sort-basenames-ascending l))) + +(defun recentf-show-basenames-descending (l) + "Filter the list of menu elements L. +Show only file names in the menu, sorted in descending order. This +filter combines the `recentf-sort-basenames-descending' and +`recentf-show-basenames' filters." + (recentf-show-basenames (recentf-sort-basenames-descending l))) + +(defun recentf-relative-filter (l) + "Filter the list of `recentf-menu-elements' L. +Show filenames relative to `default-directory'." + (setq recentf-update-menu-p t) ; force menu update + (let ((dir (expand-file-name default-directory))) + (mapcar (function + (lambda (menu-element) + (let* ((ful-path (recentf-menu-element-value menu-element)) + (rel-path (file-relative-name ful-path dir))) + (if (string-match "^\\.\\." rel-path) + menu-element + (recentf-make-menu-element rel-path ful-path))))) + l))) + +(defcustom recentf-arrange-rules + '( + ("Elisp files (%d)" ".\\.el$") + ("Java files (%d)" ".\\.java$") + ("C/C++ files (%d)" "c\\(pp\\)?$") + ) + "*List of rules used by `recentf-arrange-by-rule' to build sub-menus. +A rule is a pair (SUB-MENU-TITLE . MATCHER). SUB-MENU-TITLE is the +displayed title of the sub-menu where a '%d' `format' pattern is +replaced by the number of items in the sub-menu. MATCHER is a regexp +or a list of regexps. Items matching one of the regular expressions in +MATCHER are added to the corresponding sub-menu." + :group 'recentf-filters + :type '(repeat (cons string (repeat regexp))) + :set 'recentf-menu-customization-changed) + +(defcustom recentf-arrange-by-rule-others "Other files (%d)" + "*Title of the `recentf-arrange-by-rule' sub-menu. +This is for the menu where items that don't match any +`recentf-arrange-rules' are displayed. If nil these items are +displayed in the main recent files menu. A '%d' `format' pattern in +the title is replaced by the number of items in the sub-menu." + :group 'recentf-filters + :type '(choice (const :tag "Main menu" nil) + (string :tag "Title")) + :set 'recentf-menu-customization-changed) + +(defcustom recentf-arrange-by-rules-min-items 0 + "*Minimum number of items in a `recentf-arrange-by-rule' sub-menu. +If the number of items in a sub-menu is less than this value the +corresponding sub-menu items are displayed in the main recent files +menu or in the `recentf-arrange-by-rule-others' sub-menu if +defined." + :group 'recentf-filters + :type 'number + :set 'recentf-menu-customization-changed) + +(defcustom recentf-arrange-by-rule-subfilter nil + "*Function used by `recentf-arrange-by-rule' to filter sub-menu elements. +Nil means no filter. See also `recentf-menu-filter'. You can't use +`recentf-arrange-by-rule' itself here!" + :group 'recentf-filters + :type '(choice (const nil) function) + :set (lambda (sym val) + (if (eq val 'recentf-arrange-by-rule) + (error "Can't use `recentf-arrange-by-rule' itself here!") + (recentf-menu-customization-changed sym val)))) + +(defun recentf-match-rule-p (matcher file-path) + "Return non-nil if the rule specified by MATCHER match FILE-PATH. +See `recentf-arrange-rules' for details on MATCHER." + (if (stringp matcher) + (string-match matcher file-path) + (while (and (consp matcher) + (not (string-match (car matcher) file-path))) + (setq matcher (cdr matcher))) + matcher)) + +(defun recentf-arrange-by-rule (l) + "Filter the list of menu-elements L. +Arrange them in sub-menus following rules in `recentf-arrange-rules'." + (let ((sub-menus-number (length recentf-arrange-rules))) + (if (> sub-menus-number 0) + (let ((sub-menus (apply 'vector + (mapcar (function + (lambda (pair) + (list (car pair)))) + recentf-arrange-rules))) + other-menu-elements index min-size) + (while l + (let* ((menu-element (car l)) + (file-path (recentf-menu-element-value menu-element)) + (rules recentf-arrange-rules) + (found nil)) + (setq index 0) + (while (and (not found) rules) + (if (recentf-match-rule-p (cdar rules) file-path) + (let ((sub-menu (aref sub-menus index))) + (setq found t) + (recentf-set-menu-element-value + sub-menu + (cons menu-element (recentf-menu-element-value sub-menu))) + )) + (setq index (1+ index)) + (setq rules (cdr rules))) + (or found + (setq other-menu-elements + (cons menu-element other-menu-elements))) + (setq l (cdr l)))) + (setq index 0) + (setq l nil) + (setq min-size (if (integerp recentf-arrange-by-rules-min-items) + (max 0 recentf-arrange-by-rules-min-items) + 0)) + (while (< index sub-menus-number) + (let* ((sub-menu (aref sub-menus index)) + (sub-menu-title (recentf-menu-element-item sub-menu)) + (sub-menu-elements (recentf-menu-element-value sub-menu)) + (sub-menu-length (length sub-menu-elements))) + (if (> sub-menu-length 0) + (cond + ((< sub-menu-length min-size) + (setq other-menu-elements + (nconc sub-menu-elements other-menu-elements))) + ((>= sub-menu-length min-size) + (recentf-set-menu-element-item + sub-menu + (format sub-menu-title sub-menu-length)) + (recentf-set-menu-element-value + sub-menu + (recentf-apply-menu-filter + recentf-arrange-by-rule-subfilter + (nreverse sub-menu-elements))) + (setq l (cons sub-menu l))))) + (setq index (1+ index)))) + (if (and (stringp recentf-arrange-by-rule-others) + other-menu-elements) + (setq l + (nreverse + (cons (recentf-make-menu-element + (format recentf-arrange-by-rule-others + (length other-menu-elements)) + (recentf-apply-menu-filter + recentf-arrange-by-rule-subfilter + (nreverse other-menu-elements))) + l))) + (setq l (nconc (nreverse l) + (recentf-apply-menu-filter + recentf-arrange-by-rule-subfilter + (nreverse other-menu-elements))))))) + l)) + +(defun recentf-build-mode-rules () + "Convert `auto-mode-alist' to `recentf-arrange-rules' format." + (let ((case-fold-search recentf-case-fold-search) + (modes auto-mode-alist) + regexp mode rule-name rule rules) + (while modes + (setq regexp (caar modes)) + (setq mode (cdar modes)) + (when (symbolp mode) + (setq rule-name (symbol-name mode)) + (if (string-match "\\(.*\\)-mode$" rule-name) + (setq rule-name (match-string 1 rule-name))) + (setq rule-name (concat rule-name " (%d)")) + (setq rule (assoc rule-name rules)) + (if rule + (setcdr rule (cons regexp (cdr rule))) + (setq rules (cons (list rule-name regexp) rules)))) + (setq modes (cdr modes))) + ;; It is important to preserve auto-mode-alist order + ;; to ensure the right file <-> mode association + (nreverse rules))) + +(defun recentf-arrange-by-mode (l) + "Filter the list of menu-elements L to build sub-menus for each major mode." + (let ((recentf-arrange-rules (recentf-build-mode-rules)) + (recentf-arrange-by-rule-others "others (%d)")) + (recentf-arrange-by-rule l))) + +(defun recentf-build-dir-rules (l) + "Convert directories in menu-elements L to rules in `recentf-arrange-rules' format." + (let (dirs) + (mapcar (function + (lambda (e) + (let ((dir (file-name-directory + (recentf-menu-element-value e)))) + (or (recentf-string-member dir dirs) + (setq dirs (cons dir dirs)))))) + l) + (mapcar (function + (lambda (d) + (cons (concat d " (%d)") + (concat "\\`" d)))) + (nreverse (sort dirs 'recentf-string-lessp))))) + +(defun recentf-file-name-nondir (l) + "Filter the list of menu-elements L to show only filenames. +This simplified version of `recentf-show-basenames' does not handle +duplicates. It is used by `recentf-arrange-by-dir' as its +`recentf-arrange-by-rule-subfilter'." + (mapcar (function + (lambda (e) + (recentf-make-menu-element + (file-name-nondirectory (recentf-menu-element-value e)) + (recentf-menu-element-value e)))) + l)) + +(defun recentf-arrange-by-dir (l) + "Filter the list of menu-elements L to build sub-menus for each directory." + (let ((recentf-arrange-rules (recentf-build-dir-rules l)) + (recentf-arrange-by-rule-subfilter 'recentf-file-name-nondir) + recentf-arrange-by-rule-others) + (nreverse (recentf-arrange-by-rule l)))) + +(defvar recentf-filter-changer-state nil + "Used by `recentf-filter-changer' to hold its state.") + +(defcustom recentf-filter-changer-alist + '( + (recentf-arrange-by-mode . "*Files by Mode*") + (recentf-arrange-by-dir . "*Files by Directory*") + (recentf-arrange-by-rule . "*Files by User Rule*") + ) + "*List of filters managed by `recentf-filter-changer'. +Each filter is defined by a pair (FILTER-FUN . FILTER-LBL) where: + +- - FILTER-FUN is the function that filters menu-elements +- - FILTER-LBL is the menu item used to activate the filter" + :group 'recentf-filters + :type '(repeat (cons function string)) + :set (lambda (sym val) + (setq recentf-filter-changer-state nil) + (recentf-menu-customization-changed sym val))) + +(defun recentf-filter-changer-goto-next () + "Go to the next filter available (see `recentf-filter-changer')." + (and (consp recentf-filter-changer-state) + (setq recentf-filter-changer-state + (cdr recentf-filter-changer-state))) + (setq recentf-update-menu-p t)) + +(defun recentf-filter-changer-get-current () + "Get the current filter available (see `recentf-filter-changer')." + (if (null recentf-filter-changer-state) + (setq recentf-filter-changer-state recentf-filter-changer-alist)) + (and (consp recentf-filter-changer-state) + (car recentf-filter-changer-state))) + +(defun recentf-filter-changer-get-next () + "Get the next filter available (see `recentf-filter-changer')." + (let ((filters recentf-filter-changer-state)) + (cond ((consp filters) + (setq filters (cdr filters)) + (if (null filters) + (setq filters recentf-filter-changer-alist))) + (t + (setq filters recentf-filter-changer-alist) + (if (consp filters) + (setq filters (cdr filters))))) + (if (consp filters) + (car filters)))) + +(defun recentf-filter-changer (l) + "Manage a ring of filters. +`recentf-filter-changer-alist' defines the filters in the ring. +Actual filtering of L is delegated to the current filter in the +ring. A filter menu item is displayed allowing to dynamically activate +the next filter in the ring. If the filter ring is empty L is left +unchanged." + (let ((current-filter-item (recentf-filter-changer-get-current)) + (next-filter-item (recentf-filter-changer-get-next))) + (when current-filter-item + (setq l (recentf-apply-menu-filter (car current-filter-item) l)) + (if next-filter-item + (setq recentf-menu-filter-commands + (list (vector (cdr next-filter-item) + '(recentf-filter-changer-goto-next) + t))))) + l)) + +;;;; +;;;; Dialogs stuff +;;;; + +(defun recentf-cancel-dialog (&rest ignore) + "Cancel the current dialog. +Used by `recentf-edit-list' and `recentf-open-files' dialogs. +IGNORE arguments." + (interactive) + (kill-buffer (current-buffer)) + (message "Dialog canceled.")) + +(defvar recentf-button-keymap + (let (parent-keymap mouse-button1 keymap) + (if (featurep 'xemacs) + (setq parent-keymap widget-button-keymap + mouse-button1 [button1]) + (setq parent-keymap widget-keymap + mouse-button1 [down-mouse-1])) + (setq keymap (copy-keymap parent-keymap)) + (define-key keymap mouse-button1 #'widget-button-click) + keymap) + "Keymap used inside buttons.") + +(defvar recentf-dialog-mode-map + (let ((km (make-sparse-keymap))) + (define-key km "q" 'recentf-cancel-dialog) + (define-key km [down-mouse-1] 'widget-button-click) + (set-keymap-parent km widget-keymap) + km) + "`recentf-dialog-mode' keymap.") + +(defun recentf-dialog-mode () + "Major mode used in recentf dialogs. + +These are the special commands of `recentf-dialog-mode' mode: + q -- cancel this dialog." + (interactive) + (setq major-mode 'recentf-dialog-mode) + (setq mode-name "recentf-dialog") + (use-local-map recentf-dialog-mode-map)) + +;;;; +;;;; Hooks and Commands +;;;; + +(defun recentf-add-file-hook () + "Insert the name of the file just opened or written into `recentf-list'." + (and buffer-file-name (recentf-add-file buffer-file-name)) + nil) + +(defun recentf-remove-file-hook () + "When a buffer is killed remove a non readable file from `recentf-list'." + (and buffer-file-name (recentf-remove-if-non-readable buffer-file-name)) + nil) + +(defun recentf-update-menu-hook () + "Update the recentf menu from the current `recentf-list'." + (when recentf-update-menu-p + (condition-case nil + (progn + (setq recentf-update-menu-p nil) + (easy-menu-change recentf-menu-path + recentf-menu-title + (recentf-make-menu-items) + recentf-menu-before) + t) + (error nil)))) + +(defun recentf-dump-variable (variable &optional limit) + "Insert a \"(setq VARIABLE value)\" in the current buffer. +Optional argument LIMIT specifies a maximum length when VARIABLE value +is a list (default to the full list)." + (let ((value (symbol-value variable))) + (insert (format "(setq %S\n '(\n" variable)) + (cond ((consp value) + (if (and (integerp limit) (> limit 0)) + (setq value (recentf-trunc-list value limit))) + (mapcar (function + (lambda (e) + (insert (format " %S\n" e)))) + value)) + (t + (insert (format " %S\n" value)))) + (insert " ))\n") + )) + +;;;###autoload +(defun recentf-save-list () + "Save the current `recentf-list' to the file `recentf-save-file'." + (interactive) + (with-temp-buffer + (erase-buffer) + (insert (format recentf-save-file-header (current-time-string))) + (recentf-dump-variable 'recentf-list recentf-max-saved-items) + (recentf-dump-variable 'recentf-filter-changer-state) + (if (file-writable-p recentf-save-file) + (write-region (point-min) (point-max) recentf-save-file)) + (kill-buffer (current-buffer))) + nil) + +(defvar recentf-edit-selected-items nil + "Used by `recentf-edit-list'. +Holds list of files to be deleted from `recentf-list'.") + +(defun recentf-edit-list-action (widget &rest ignore) + "Checkbox WIDGET action. +Used by `recentf-edit-list' to select/unselect a file. IGNORE other +arguments." + (let ((value (widget-get widget ':tag))) + ;; if value is already in the selected items + (if (memq value recentf-edit-selected-items) + ;; then remove it + (progn + (setq recentf-edit-selected-items + (delq value recentf-edit-selected-items)) + (message "%s removed from selection." value)) + ;; else add it + (progn + (setq recentf-edit-selected-items + (nconc (list value) recentf-edit-selected-items)) + (message "%s added to selection." value))))) + +;;;###autoload +(defun recentf-edit-list () + "Allow the user to edit the files that are kept in the recent list." + (interactive) + (with-current-buffer (get-buffer-create (concat "*" recentf-menu-title " - Edit list*")) + (switch-to-buffer (current-buffer)) + (kill-all-local-variables) + (let ((inhibit-read-only t)) + (erase-buffer)) + (let ((all (recentf-overlay-lists))) + ;; Delete all the overlays. + (mapcar 'recentf-delete-overlay (car all)) + (mapcar 'recentf-delete-overlay (cdr all))) + (setq recentf-edit-selected-items nil) + ;; Insert the dialog header + (widget-insert "Select the files to be deleted from the 'recentf-list'.\n\n") + (widget-insert "Click on Ok to update the list. ") + (widget-insert "Click on Cancel or type \"q\" to quit.\n") + ;; Insert the list of files as checkboxes + (mapcar (function + (lambda (item) + (widget-create 'checkbox + :value nil ; unselected checkbox + :format "\n %[%v%] %t" + :tag item + :notify 'recentf-edit-list-action))) + recentf-list) + (widget-insert "\n\n") + ;; Insert the Ok button + (widget-create 'push-button + :button-keymap recentf-button-keymap ; XEmacs + :keymap recentf-button-keymap ; Emacs + :notify (lambda (&rest ignore) + (if recentf-edit-selected-items + (progn (kill-buffer (current-buffer)) + (mapcar (function + (lambda (item) + (setq recentf-list + (delq item recentf-list)))) + recentf-edit-selected-items) + (message "%S file(s) removed from the list" + (length recentf-edit-selected-items)) + (setq recentf-update-menu-p t)) + (message "No file selected."))) + "Ok") + (widget-insert " ") + ;; Insert the Cancel button + (widget-create 'push-button + :button-keymap recentf-button-keymap ; XEmacs + :keymap recentf-button-keymap ; Emacs + :notify 'recentf-cancel-dialog + "Cancel") + (recentf-dialog-mode) + (widget-setup) + (goto-char (point-min)))) + +;;;###autoload +(defun recentf-cleanup () + "Remove all non-readable and excluded files from `recentf-list'." + (interactive) + (let ((count (length recentf-list))) + (setq recentf-list + (delq nil + (mapcar (function + (lambda (filename) + (and + (not filename) + (file-readable-p filename) + (recentf-include-p filename) + filename))) + recentf-list))) + (setq count (- count (length recentf-list))) + (message "%s removed from the list" + (cond ((= count 0) "No file") + ((= count 1) "One file") + (t (format "%d files" count))))) + (setq recentf-update-menu-p t)) + +(defun recentf-open-files-action (widget &rest ignore) + "Button WIDGET action used by `recentf-open-files' to open a file. +IGNORE other arguments." + (kill-buffer (current-buffer)) + (funcall recentf-menu-action (widget-value widget))) + +(defvar recentf-open-files-item-shift "" + "String used by `recentf-open-files' to shift right sub-menu items.") + +(defun recentf-open-files-item (menu-element) + "Insert MENU-ELEMENT item in the current interaction buffer." + (let ((menu-item (car menu-element)) + (file-path (cdr menu-element))) + (if (consp file-path) ; This is a sub-menu + (let* ((shift recentf-open-files-item-shift) + (recentf-open-files-item-shift (concat shift " "))) + (widget-create 'item + :tag menu-item + :sample-face 'bold + :format (concat shift "%{%t%}:\n")) + (mapcar 'recentf-open-files-item + file-path) + (widget-insert "\n")) + (widget-create 'push-button + :button-keymap recentf-button-keymap ; XEmacs + :keymap recentf-button-keymap ; Emacs + :button-face 'default + :tag menu-item + :help-echo (concat "Open " file-path) + :format (concat recentf-open-files-item-shift "%[%t%]") + :notify 'recentf-open-files-action + file-path) + (widget-insert "\n")))) + +;;;###autoload +(defun recentf-open-files (&optional files buffer-name) + "Display buffer allowing user to choose a file from recently-opened list. +The optional argument FILES may be used to specify the list, otherwise +`recentf-list' is used. The optional argument BUFFER-NAME specifies +which buffer to use for the interaction." + (interactive) + (if (null files) + (setq files recentf-list)) + (if (null buffer-name) + (setq buffer-name (concat "*" recentf-menu-title "*"))) + (with-current-buffer (get-buffer-create buffer-name) + (switch-to-buffer (current-buffer)) + (kill-all-local-variables) + (let ((inhibit-read-only t)) + (erase-buffer)) + (let ((all (recentf-overlay-lists))) + ;; Delete all the overlays. + (mapcar 'recentf-delete-overlay (car all)) + (mapcar 'recentf-delete-overlay (cdr all))) + ;; Insert the dialog header + (widget-insert "Click on a file to open it. ") + (widget-insert "Click on Cancel or type \"q\" to quit.\n\n" ) + ;; Insert the list of files as buttons + (let ((recentf-open-files-item-shift "")) + (mapcar 'recentf-open-files-item + (recentf-apply-menu-filter + recentf-menu-filter + (mapcar 'recentf-make-default-menu-element files)))) + (widget-insert "\n") + ;; Insert the Cancel button + (widget-create 'push-button + :button-keymap recentf-button-keymap ; XEmacs + :keymap recentf-button-keymap ; Emacs + :notify 'recentf-cancel-dialog + "Cancel") + (recentf-dialog-mode) + (widget-setup) + (goto-char (point-min)))) + +;;;###autoload +(defun recentf-open-more-files () + "Allow the user to open files that are not in the menu." + (interactive) + (recentf-open-files (nthcdr recentf-max-menu-items recentf-list) + (concat "*" recentf-menu-title " - More*"))) + +;;;###autoload +(defun recentf-mode (&optional arg) + "Toggle recentf mode. +With prefix ARG, turn recentf mode on if and only if ARG is positive. +Returns the new status of recentf mode (non-nil means on). + +When recentf mode is enabled, it maintains a menu for visiting files that +were operated on recently." + (interactive "P") + (let ((on-p (if arg + (> (prefix-numeric-value arg) 0) + (not recentf-mode)))) + (cond + ;; `recentf-mode' enabled. + (on-p + ;; Rebuild the `recentf-virtual-pathes-alist' when + ;; `recentf-mode' is enabled. Normally this is the only time + ;; this function must be called. + (recentf-rebuild-virtual-pathes) + (unless recentf-initialized-p + (setq recentf-initialized-p t) + (if (file-readable-p recentf-save-file) + (load-file recentf-save-file)) + (setq recentf-update-menu-p t) + (add-hook 'find-file-hooks 'recentf-add-file-hook) + (add-hook 'write-file-hooks 'recentf-add-file-hook) + (add-hook (if (featurep 'xemacs) + 'activate-menubar-hook + 'menu-bar-update-hook) + 'recentf-update-menu-hook) + (add-hook 'kill-emacs-hook 'recentf-save-list)) + ;; maybe we have to do an initial cleanup + (if (eq recentf-auto-cleanup 'enable) + (recentf-cleanup))) + + ;; `recentf-mode' disabled. + (recentf-initialized-p + (setq recentf-initialized-p nil) + (recentf-save-list) + (easy-menu-remove-item nil recentf-menu-path recentf-menu-title) + (remove-hook 'find-file-hooks 'recentf-add-file-hook) + (remove-hook 'write-file-hooks 'recentf-add-file-hook) + (remove-hook (if (featurep 'xemacs) + 'activate-menubar-hook + 'menu-bar-update-hook) + 'recentf-update-menu-hook) + (remove-hook 'kill-emacs-hook 'recentf-save-list) + ;; cancel all timers + (recentf-cancel-cleanup-timer))) + (setq recentf-mode on-p))) + +(provide 'recentf) + +(run-hooks 'recentf-load-hook) + +;;; recentf.el ends here diff --git a/lisp/rw-hunspell.el b/lisp/rw-hunspell.el new file mode 100644 index 0000000..cc08469 --- /dev/null +++ b/lisp/rw-hunspell.el @@ -0,0 +1,400 @@ +;;; rw-hunspell.el --- special functions for Hunspell in ispell.el +;; +;; Copyright (C) 2009 Ralf Wachinger +;; +;; Author: Ralf Wachinger +;; Version: 0.2 +;; Keywords: ispell +;; Compatibility: GNU Emacs 23.x +;; +;; This file is NOT part of GNU Emacs. +;; +;; 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, see . +;; +;;; Commentary: +;; +;; Additions for Hunspell, which find all existing Hunspell dictionaries +;; in the given directories, generate a special alist for Hunspell, and +;; optionally create a special menu for selecting the dictionaries. +;; +;; Save rw-hunspell.el in a convenient directory, preferably in +;; your `load-path'. Add the following to your `user-init-file': +;; +;; (require 'rw-hunspell) +;; +;; When the creation starts: +;; a) keyboard: 'M-x rw-hunspell-setup RET' +;; b) menubar: Tools --> Spell Checking --> Set up Hunspell +;; c) automatically when Hunspell is used the first time +;; d) `user-init-file', after setting the user options: (rw-hunspell-setup) +;; e) when `rw-ispell-change-dictionary' (see rw-ispell.el) is called +;; +;; ESSENTIAL: `ispell-program-name' must be set to the Hunspell program name. +;; ATTENTION: Hunspell is not supported by ispell.el before GNU Emacs 23.x. +;; `ispell-dictionary' can be set, in addition to the default dictionary. +;; `ispell-local-dictionary-alist' can be set, as manual list in addition to +;; or overriding the automatically generated `rw-hunspell-dictionary' alist. +;; +;; Todo: +;; Make the program more dynamic, particularly the dictionary menu. +;; Parsing MS Windows locales from environmental variable LANG, e. g. "DEU". +;; Possibly full integration in ispell.el, analogous to the functions +;; ispell-find-aspell-dictionaries and ispell-aspell-find-dictionary. +;; +;;; Change Log: +;; +;; 2009-03-29 (0.2) +;; +;; * function definitions for `canonicalize-coding-system-name' +;; and `coding-system-from-name' added. These are new functions +;; in the CVS-Emacs from 2009-01-27, rw-hunspell.el needs it. +;; They will be removed, when the stable Emacs-23.1 comes out. +;; +;; 2009-03-20 (0.1) +;; Initial Release. +;; +;;; Code: + +(require 'ispell) +(require 'easymenu) + +;; User options. +;; This options must be set before Hunspell runs for the first time. + +(defgroup rw-hunspell nil + "Hunspell customization options." + :group 'ispell) + +(defcustom rw-hunspell-dicpath-list nil + "*List of dictionary directories for Hunspell. +If not set, the directories from environmental variable DICPATH are taken." + :type '(repeat string) + :group 'rw-hunspell) + +(defcustom rw-hunspell-default-dictionary "en_US" + "*Default dictionary for Hunspell, e. g. \"en_US\" (basic file name) +or \"en_US_Hunspell\" (generated dictionary name). If not set, +the dictionary from environmental variables DICTIONARY or LANG are taken." + :type 'string + :group 'rw-hunspell) + +(defcustom rw-hunspell-make-dictionary-menu nil + "*Make menu with all found dictionaries when non-nil. +Needs rw-language-and-country-codes.el for full language and country names." + :type 'boolean + :group 'rw-hunspell) + +(defcustom rw-hunspell-use-rw-ispell nil + "*Use `rw-ispell-change-dictionary' when non-nil. +Needs rw-ispell.el when non-nil." + :type 'boolean + :group 'rw-hunspell) + +(defcustom rw-hunspell-delete-dictionary-base-alist t + "*Delete `ispell-dictionary-base-alist' for the emacs session when non-nil. +That alist is not useful for Hunspell, because it needs other parameters." + :type 'boolean + :group 'rw-hunspell) + +;; Internal. + +(defvar rw-hunspell-dictionary-alist nil + "Automatically set, do not set manually. +List of automatically generated dictionaries with recognized encoding. +It has the same format as `ispell-dictionary-alist'.") + +(defvar rw-hunspell-no-encoding-recognized-alist nil + "Automatically set, do not set manually. +List of dictionaries, for which emacs can't recognize the encoding. +It has the same format as `ispell-dictionary-alist'.") + +;; For Emacs-23.0-Versions before 2009-01-27. +;; CVSWeb URLs: +;; http://cvs.savannah.gnu.org/viewcvs/emacs/lisp/international/mule-cmds.el?cvsroot=emacs&r1=1.355&r2=1.356 +(when (not (and (fboundp 'canonicalize-coding-system-name) + (fboundp 'coding-system-from-name))) + ;; Canonicalize the coding system name NAME by removing some prefixes + ;; and delimiter characters. Support function of + ;; coding-system-from-name. + (defun canonicalize-coding-system-name (name) + (if (string-match "^iso[-_ ]?[0-9]" name) + ;; "iso-8859-1" -> "8859-1", "iso-2022-jp" ->"2022-jp" + (setq name (substring name (1- (match-end 0))))) + (let ((idx (string-match "[-_ /]" name))) + ;; Delete "-", "_", " ", "/" but do distinguish "16-be" and "16be". + (while idx + (if (and (>= idx 2) + (eq (string-match "16-[lb]e$" name (- idx 2)) + (- idx 2))) + (setq idx (string-match "[-_ /]" name (match-end 0))) + (setq name (concat (substring name 0 idx) (substring name (1+ idx))) + idx (string-match "[-_ /]" name idx)))) + name)) + + (defun coding-system-from-name (name) + "Return a coding system whose name matches with NAME (string or symbol)." + (let (sym) + (if (stringp name) (setq sym (intern name)) + (setq sym name name (symbol-name name))) + (if (coding-system-p sym) + sym + (let ((eol-type + (if (string-match "-\\(unix\\|dos\\|mac\\)$" name) + (prog1 (intern (match-string 1 name)) + (setq name (substring name 0 (match-beginning 0))))))) + (setq name (canonicalize-coding-system-name (downcase name))) + (catch 'tag + (dolist (elt (coding-system-list)) + (if (string= (canonicalize-coding-system-name (symbol-name elt)) + name) + (throw 'tag (if eol-type (coding-system-change-eol-conversion + elt eol-type) + elt)))))))))) + +(defun rw-hunspell-find-dictionaries () + "Find Hunspell's dictionaries." + (if (and (boundp 'ispell-really-hunspell) + ispell-really-hunspell) + (let ((dictionary-directories + (if rw-hunspell-dicpath-list + (mapcar #'file-name-as-directory + rw-hunspell-dicpath-list) + (if (getenv "DICPATH") + (mapcar #'file-name-as-directory + (split-string (getenv "DICPATH") path-separator)) + (list)))) + (hunspell-program-directory + (if (file-name-absolute-p ispell-program-name) + (file-name-directory ispell-program-name) + (if (executable-find ispell-program-name) + (file-name-directory (executable-find ispell-program-name)) + nil))) + (dictionaries (list))) + (add-to-list 'dictionary-directories hunspell-program-directory) + (dolist (directory dictionary-directories) + (setq dictionaries + (append + dictionaries + (mapcar #'file-name-sans-extension + (directory-files directory t ".+\\.dic"))))) + dictionaries) + nil)) + +(defun rw-hunspell-make-dictionary-alist () + "Make `rw-hunspell-dictionary-alist' for Hunspell." + (dolist (dictionary (rw-hunspell-find-dictionaries)) + (condition-case () + ;; Only for *.dic files with *.aff files. + ;; In the OpenOffice dictionary directory there are + ;; spellchecker dictionaries with files *.aff und *.dic + ;; for every dictionary, this dictionaries are included. + ;; Moreover, there are hyphenation dictionaries with files hyph*.dic + ;; without files *.aff, this dictionaries are not included. + (when (file-exists-p (concat dictionary ".aff")) + (let (;; Encoding and wordchars are read from the *.aff file. + (encoding "") + (wordchars "") + ;; Unique dictionary name + (dictionary-name + (concat (file-name-nondirectory dictionary) + "_" (file-name-nondirectory + (directory-file-name + (file-name-directory dictionary)))))) + (with-temp-buffer + (insert-file-contents (concat dictionary ".aff")) + ;; Encoding declaration line, e. g. "SET ISO8859-1" + (when (search-forward-regexp "^SET " nil t) + (setq encoding + (car (last (split-string + (buffer-substring + (point) + (progn (end-of-line) (point))))))))) + (when (coding-system-from-name encoding) + (with-temp-buffer + (let ((coding-system-for-read + (coding-system-from-name encoding))) + (insert-file-contents (concat dictionary ".aff"))) + (setq wordchars + ;; Wordchars (correspond to otherchars) declaration line. + ;; There are *.aff-files which do not define wordchars. + (if (search-forward-regexp "^WORDCHARS " nil t) + (regexp-opt + (mapcar + 'char-to-string + (car (last (split-string + (buffer-substring + (point) + (progn (end-of-line) (point)))))))) + "")))) + ;; Entry for every found dictionary with recognized encoding. + (when (coding-system-from-name encoding) + (add-to-list + 'rw-hunspell-dictionary-alist + (list dictionary-name + "[[:alpha:]]" + "[^[:alpha:]]" + wordchars + t + (list "-d" dictionary) + nil + (coding-system-from-name encoding)))) + ;; Encoding, that emacs can't recognize. + (unless (coding-system-from-name encoding) + (add-to-list + 'rw-hunspell-no-encoding-recognized-alist + (list (concat dictionary-name "_" encoding) + "[[:alpha:]]" + "[^[:alpha:]]" + wordchars + t + (list "-d" dictionary) + nil + 'raw-text))))) + (file-error + nil))) + (rw-hunspell-make-default-dictionary-entry) + (when (and rw-hunspell-dictionary-alist + rw-hunspell-delete-dictionary-base-alist) + (setq ispell-dictionary-base-alist nil))) + +(defun rw-hunspell-make-default-dictionary-entry () + "Make a default dictionary entry for the specified dictionary." + (catch 'found + (let ((locale (car (split-string (getenv "LANG") "[.@]")))) + (dolist (entry (append ispell-local-dictionary-alist + rw-hunspell-dictionary-alist)) + (let* ((name (or (car entry) "default")) + (full-file-name (car (last (nth 5 entry)))) + (file-name (file-name-nondirectory full-file-name)) + (wordchars (nth 3 entry)) + (encoding (nth 7 entry))) + (when (or (string= name "default") + (string= rw-hunspell-default-dictionary name) + (string= rw-hunspell-default-dictionary file-name) + (and (not rw-hunspell-default-dictionary) + (string= (or (getenv "DICTIONARY") locale) + file-name))) + (add-to-list + 'rw-hunspell-dictionary-alist + (list nil + "[[:alpha:]]" + "[^[:alpha:]]" + wordchars + t + (list "-d" full-file-name) + nil + (coding-system-from-name encoding))) + (throw 'found t))))))) + +(defun rw-hunspell-make-dictionary-menu () + "Make menu with all automatically found and manually set dictionaries." + (let (menu-local + menu-global) + ;; Automatically generated and manually set dictionaries. + (dolist (entry (append ispell-local-dictionary-alist + rw-hunspell-dictionary-alist)) + (let* ((name (or (car entry) "default")) + (file-name (file-name-nondirectory (car (last (nth 5 entry))))) + ;; Long names for dictionaries in the menu. + (long-name + (concat + (if (string= name "default") "- " "") + (if (fboundp 'rw-lacc-replace-code-in-string) + (concat (capitalize + (rw-lacc-replace-code-in-string file-name)) + " (" name ")") + name) + (if (string= name "default") " -" "")))) + (setq menu-global + (append menu-global + (list + (vector + long-name + (if (and rw-hunspell-use-rw-ispell + (fboundp 'rw-ispell-change-dictionary)) + (list 'rw-ispell-change-dictionary name t) + (list 'ispell-change-dictionary name t)) + :style 'toggle + :selected (list + 'string= 'ispell-dictionary name))))) + (setq menu-local + (append menu-local + (list + (vector + long-name + (if (and rw-hunspell-use-rw-ispell + (fboundp 'rw-ispell-change-dictionary)) + (list 'rw-ispell-change-dictionary name) + (list 'ispell-change-dictionary name)) + :style 'toggle + :selected (list + 'string= 'ispell-local-dictionary name))))))) + (setq menu-global (sort menu-global + #'(lambda (element1 element2) + (string< (aref element1 0) (aref element2 0))))) + (push "Select global dictionary" menu-global) + (setq menu-local (sort menu-local + #'(lambda (element1 element2) + (string< (aref element1 0) (aref element2 0))))) + (push "Select local dictionary" menu-local) + (easy-menu-add-item ispell-menu-map '() menu-global) + (easy-menu-add-item ispell-menu-map '() menu-local) + (easy-menu-add-item + ispell-menu-map '("Select global dictionary") + ["" nil + :label (format "Global personal dictionary: %s" + (file-name-nondirectory + (or ispell-personal-dictionary "none")))]) + (easy-menu-add-item + ispell-menu-map '("Select local dictionary") + ["" nil + :label (format "Local personal dictionary: %s" + (file-name-nondirectory + (or ispell-local-pdict "none")))]))) + +;; User functions. + +(defun rw-hunspell-setup () + "Generate hunspell dictionary alist and menu, if they don't exist." + (interactive) + (unless rw-hunspell-dictionary-alist + (ispell-check-version) + (unless (boundp 'ispell-really-hunspell) + (error "Hunspell is not supported on %s" (emacs-version))) + (unless (and (boundp 'ispell-really-hunspell) ispell-really-hunspell) + (error "Current spellchecker is not Hunspell, ispell-program-name is %s" + ispell-program-name)) + (rw-hunspell-make-dictionary-alist) + (when rw-hunspell-make-dictionary-menu + (rw-hunspell-make-dictionary-menu)))) + +(easy-menu-add-item + ispell-menu-map '() + ["Set up Hunspell" rw-hunspell-setup + :visible (not rw-hunspell-dictionary-alist)]) + +;; Hooks. + +(defun rw-hunspell-setup-hook () + "Set up all for hunspell. +This hook is run when hunspell is used for the first time." + (rw-hunspell-setup) + (setq ispell-base-dicts-override-alist rw-hunspell-dictionary-alist)) + +(add-hook 'ispell-initialize-spellchecker-hook + 'rw-hunspell-setup-hook) + +(provide 'rw-hunspell) + +;;; rw-hunspell.el ends here. diff --git a/lisp/rw-ispell.el b/lisp/rw-ispell.el new file mode 100644 index 0000000..1b88e22 --- /dev/null +++ b/lisp/rw-ispell.el @@ -0,0 +1,195 @@ +;;; rw-ispell.el --- additional functions for ispell.el +;; +;; Copyright (C) 2009 Ralf Wachinger +;; +;; Author: Ralf Wachinger +;; Version: 0.1 +;; Keywords: ispell +;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x +;; +;; This file is NOT part of GNU Emacs. +;; +;; 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, see . +;; +;;; Commentary: +;; +;; Associating freely personal dictionaries with +;; general dictionaries for Ispell, Aspell and Hunspell, +;; creating personal dictionary files if necessary, and +;; changing general and personal dictionaries at the same time. +;; +;; Save rw-ispell.el in a convenient directory, preferably in +;; your `load-path'. Add the following to your `user-init-file': +;; +;; (require 'rw-ispell) +;; +;; When the setup starts: +;; a) keyboard: 'M-x rw-ispell-set-up-pdicts RET' +;; b) menubar: Tools --> Spell Checking --> Set up Personal Dictionaries +;; c) automatically when the spellchecker is used the first time +;; d) `user-init-file', after setting the user options: +;; (rw-ispell-set-up-pdicts) +;; +;; Todo: +;; Settings in `ispell-message-dictionary-alist' are not considered yet. +;; Possibly full integration in ispell.el. +;; +;;; Change Log: +;; +;; 2009-03-20 (0.1) +;; Initial Release. +;; +;;; Code: + +(require 'ispell) +(require 'easymenu) + +;; User options. + +(defgroup rw-ispell nil + "Additional ispell customization options." + :group 'ispell) + +(defcustom rw-ispell-language-pdict-alist nil + "*List used to select a new personal dictionary +according to a dictionary regexp, normally a part of the dictionary name. +It consists of pairs (REGEXP . DICTIONARY). +If the REGEXP of the last pair is an empty string, +then DICTIONARY is the default personal dictionary. +If DICTIONARY is a file name without path, user's home directory is taken. +E.g. you may use the following value: + '((\"^en\" . \"~/.pdict_english\") + (\"^de\" . \"~/.pdict_deutsch\") + (\"\" . \"~/.pdict_default\"))" + :type '(repeat (cons regexp string)) + :group 'rw-ispell) + +(defcustom rw-ispell-create-pdict-files nil + "*Create empty personal dictionary files, when they don't exist. +Needed when the spellchecker can't create the files by itself." + :type 'boolean + :group 'rw-ispell) + +;; Internal. + +(defvar rw-ispell-is-set-up nil + "Flag if the personal dictionaries are set up.") + +(defun rw-ispell-create-pdict-file (element) + "Create an empty personal dictionary file, if it doesn't exist already." + (let ((file (expand-file-name (cdr element) "~/"))) + (unless (file-exists-p file) + (when rw-ispell-create-pdict-files + (with-temp-file file t) + (message "Created file %s" file))))) + +;; User functions. + +(defun rw-ispell-set-up-pdicts () + "Set up personal dictionaries according to `rw-ispell-language-pdict-alist'." + (interactive) + (ispell-check-version) + (let ((default-pdict (or (assoc-default "" rw-ispell-language-pdict-alist) + (getenv "WORDLIST") + "~/.personal_dictionary"))) + ;; At least one personal dictionary. + (add-to-list 'rw-ispell-language-pdict-alist + (cons "" default-pdict) 'append) + ;; Absolute paths for every dictionary. + (setq rw-ispell-language-pdict-alist + (mapcar #'(lambda (pair) + (cons (car pair) (expand-file-name (cdr pair) "~/"))) + rw-ispell-language-pdict-alist)) + ;; A file for every dictionary must exist. + (mapc #'rw-ispell-create-pdict-file rw-ispell-language-pdict-alist) + ;; A global dictionary must be set. + (setq ispell-personal-dictionary + (expand-file-name + (assoc-default "" rw-ispell-language-pdict-alist)))) + (setq rw-ispell-is-set-up t)) + +(add-hook 'ispell-initialize-spellchecker-hook + 'rw-ispell-set-up-pdicts) + +(defun rw-ispell-change-dictionary (dict &optional arg) + "Change to dictionary DICT for Ispell, and to +associated personal dictionary according to `rw-ispell-language-pdict-alist'. +With a prefix arg, set it \"globally\", for all buffers. +Without a prefix arg, set it \"locally\", just for this buffer. + +By just answering RET you can find out what the current dictionary is." + (interactive + (list (completing-read + "Use new dictionary (RET for current, SPC to complete): " + (and (fboundp 'ispell-valid-dictionary-list) + (mapcar 'list (ispell-valid-dictionary-list))) + nil t) + current-prefix-arg)) + ;; General dictionary. + (ispell-change-dictionary dict arg) + ;; Personal dictionary. + (unless (equal dict "") + (let ((pdict (assoc-default + dict + rw-ispell-language-pdict-alist + #'string-match))) + (when pdict + (if arg + (setq ispell-personal-dictionary pdict) + (setq ispell-local-pdict pdict)))))) + +(defun rw-ispell-change-personal-dictionary (dict &optional arg) + "Change to personal dictionary DICT for the spellchecker. +With a prefix arg, set it \"globally\", for all buffers. +Without a prefix arg, set it \"locally\", just for this buffer." + (interactive + (list + (completing-read + "Use new personal dictionary (RET for current, SPC to complete): " + (mapcar 'cdr rw-ispell-language-pdict-alist) + nil t) + current-prefix-arg)) + ;; This relies on completing-read's bug of returning "" for no match + (cond ((equal dict "") + (message "Using %s personal dictionary %s" + (if arg "global" "local") + (if arg ispell-personal-dictionary ispell-local-pdict))) + (t + (if arg + (setq ispell-personal-dictionary dict) + (setq ispell-local-pdict dict)) + (message "%s personal dictionary set to %s" + (if arg "Global" "Local") + dict)))) + +(easy-menu-add-item + ispell-menu-map '() + ["Set up Personals Dictionaries" rw-ispell-set-up-pdicts + :visible (not rw-ispell-is-set-up)]) + +;; Menu items analogous to "Change dictionary..." + +(easy-menu-add-item + ispell-menu-map '() + ["Change Dictionary with Personal..." rw-ispell-change-dictionary + :visible rw-ispell-is-set-up]) + +(easy-menu-add-item + ispell-menu-map '() + ["Change Personal Dictionary..." rw-ispell-change-personal-dictionary + :visible rw-ispell-is-set-up]) + +(provide 'rw-ispell) + +;;; rw-ispell.el ends here. diff --git a/lisp/rw-language-and-country-codes.el b/lisp/rw-language-and-country-codes.el new file mode 100644 index 0000000..e6bce1c --- /dev/null +++ b/lisp/rw-language-and-country-codes.el @@ -0,0 +1,557 @@ +;;; rw-language-and-country-codes.el --- Language & Country Codes +;; +;; Copyright (C) 2009 Ralf Wachinger +;; +;; Author: Ralf Wachinger +;; Version: 0.1 +;; Keywords: language +;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x +;; +;; This file is NOT part of GNU Emacs. +;; +;; 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, see . +;; +;;; Commentary: +;; +;; Language and country codes with two (or three) letters, +;; and functions, which return the full language and country names. +;; +;;; Change Log: +;; +;; 2009-03-20 (0.1) +;; Initial Release. +;; +;;; Code: + +;; Language codes +;; http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes + +(defconst rw-lacc-language-codes + '(("aa" . "Afar") + ("ab" . "Abkhazian") + ("ae" . "Avestan") + ("af" . "Afrikaans") + ("ak" . "Akan") + ("am" . "Amharic") + ("an" . "Aragonese") + ("ar" . "Arabic") + ("as" . "Assamese") + ("av" . "Avaric") + ("ay" . "Aymara") + ("az" . "Azerbaijani") + ("ba" . "Bashkir") + ("be" . "Belarusian") + ("bg" . "Bulgarian") + ("bh" . "Bihari") + ("bi" . "Bislama") + ("bm" . "Bambara") + ("bn" . "Bengali") + ("bo" . "Tibetan") + ("br" . "Breton") + ("bs" . "Bosnian") + ("ca" . "Catalan") + ("ce" . "Chechen") + ("ch" . "Chamorro") + ("co" . "Corsican") + ("cr" . "Cree") + ("cs" . "Czech") + ("cu" . "Church Slavic") + ("cv" . "Chuvash") + ("cy" . "Welsh") + ("da" . "Danish") + ("de" . "German") + ("dv" . "Divehi") + ("dz" . "Dzongkha") + ("ee" . "Ewe") + ("el" . "Greek") + ("en" . "English") + ("eo" . "Esperanto") + ("es" . "Spanish") + ("et" . "Estonian") + ("eu" . "Basque") + ("fa" . "Persian") + ("ff" . "Fulfulde") + ("fi" . "Finnish") + ("fj" . "Fijian") + ("fo" . "Faroese") + ("fr" . "French") + ("fy" . "Western Frisian") + ("ga" . "Irish") + ("gd" . "Scottish Gaelic") + ("gl" . "Galician") + ("gn" . "Guaraný") + ("gu" . "Gujarati") + ("gv" . "Manx") + ("ha" . "Hausa") + ("he" . "Hebrew") + ("hi" . "Hindi") + ("ho" . "Hiri Motu") + ("hr" . "Croatian") + ("ht" . "Haitian") + ("hu" . "Hungarian") + ("hy" . "Armenian") + ("hz" . "Herero") + ("ia" . "Interlingua") + ("id" . "Indonesian") + ("ie" . "Interlingue") + ("ig" . "Igbo") + ("ii" . "Sichuan Yi") + ("ik" . "Inupiaq") + ("io" . "Ido") + ("is" . "Icelandic") + ("it" . "Italian") + ("iu" . "Inuktitut") + ("ja" . "Japanese") + ("jv" . "Javanese") + ("ka" . "Georgian") + ("kg" . "Kongo") + ("ki" . "Kikuyu") + ("kj" . "Kwanyama") + ("kk" . "Kazakh") + ("kl" . "Kalaallisut") + ("km" . "Khmer") + ("kn" . "Kannada") + ("ko" . "Korean") + ("kr" . "Kanuri") + ("ks" . "Kashmiri") + ("ku" . "Kurdish") + ("kv" . "Komi") + ("kw" . "Cornish") + ("ky" . "Kirghiz") + ("la" . "Latin") + ("lb" . "Luxembourgish") + ("lg" . "Ganda") + ("li" . "Limburgish") + ("ln" . "Lingala") + ("lo" . "Lao") + ("lt" . "Lithuanian") + ("lu" . "Luba-Katanga") + ("lv" . "Latvian") + ("mg" . "Malagasy") + ("mh" . "Marshallese") + ("mi" . "Maori") + ("mk" . "Macedonian") + ("ml" . "Malayalam") + ("mn" . "Monglian") + ("mr" . "Marathi") + ("ms" . "Malay") + ("mt" . "Maltese") + ("my" . "Burmese") + ("na" . "Nauru") + ("nb" . "Norwegian Bokmýl") + ("nd" . "North Ndebele") + ("ne" . "Nepali") + ("ng" . "Owambo") + ("nl" . "Dutch") + ("nn" . "Norwegian Nynorsk") + ("no" . "Norwegian") + ("nr" . "South Ndebele") + ("nv" . "Navajo") + ("ny" . "Chichewa") + ("oc" . "Occitan") + ("oj" . "Ojibwa") + ("om" . "Oromo") + ("or" . "Oriya") + ("os" . "Ossetian") + ("pa" . "Panjabi") + ("pi" . "Pali") + ("pl" . "Polish") + ("ps" . "Pashto") + ("pt" . "Portuguese") + ("qu" . "Quechua") + ("rm" . "Raeto-Romance") + ("rn" . "Kirundi") + ("ro" . "Romanian") + ("ru" . "Russian") + ("rw" . "Kinyarwanda") + ("sa" . "Sanskrit") + ("sc" . "Sardinian") + ("sd" . "Sindhi") + ("se" . "Northern Sami") + ("sg" . "Sango") + ("sh" . "Serbo-Croatian") + ("si" . "Sinhala") + ("sk" . "Slovak") + ("sl" . "Slovenian") + ("sm" . "Samoan") + ("sn" . "Shona") + ("so" . "Somali") + ("sq" . "Albanian") + ("sr" . "Serbian") + ("ss" . "Swati") + ("st" . "Southern Sotho") + ("su" . "Sundanese") + ("sv" . "Swedish") + ("sw" . "Swahili") + ("ta" . "Tamil") + ("te" . "Telugu") + ("tg" . "Tajik") + ("th" . "Thai") + ("ti" . "Tigrinya") + ("tk" . "Turkmen") + ("tl" . "Tagalog") + ("tn" . "Tswana") + ("to" . "Tonga") + ("tr" . "Turkish") + ("ts" . "Tsonga") + ("tt" . "Tatar") + ("tw" . "Twi") + ("ty" . "Tahitian") + ("ug" . "Uighur") + ("uk" . "Ukrainian") + ("ur" . "Urdu") + ("uz" . "Uzbek") + ("ve" . "Venda") + ("vi" . "Vietnamese") + ("vo" . "Volapýk") + ("wa" . "Walloon") + ("wo" . "Wolof") + ("xh" . "Xhosa") + ("yi" . "Yiddish") + ("yo" . "Yoruba") + ("za" . "Zhuang") + ("zh" . "Chinese") + ("zu" . "Zulu"))) + +;; Country codes +;; http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 + +(defconst rw-lacc-country-codes + '(("AD" . "Andorra") + ("AE" . "United Arab Emirates") + ("AF" . "Afghanistan") + ("AG" . "Antigua and Barbuda") + ("AI" . "Anguilla") + ("AL" . "Albania") + ("AM" . "Armenia") + ("AN" . "Netherlands Antilles") + ("AO" . "Angola") + ("AQ" . "Antarctica") + ("AR" . "Argentina") + ("AS" . "American Samoa") + ("AT" . "Austria") + ("AU" . "Australia") + ("AW" . "Aruba") + ("AX" . "ýland Islands") + ("AZ" . "Azerbaijan") + ("BA" . "Bosnia and Herzegovina") + ("BB" . "Barbados") + ("BD" . "Bangladesh") + ("BE" . "Belgium") + ("BF" . "Burkina Faso") + ("BG" . "Bulgaria") + ("BH" . "Bahrain") + ("BI" . "Burundi") + ("BJ" . "Benin") + ("BL" . "Saint Barthýlemy") + ("BM" . "Bermuda") + ("BN" . "Brunei") + ("BO" . "Bolivia") + ("BR" . "Brazil") + ("BS" . "Bahamas") + ("BT" . "Bhutan") + ("BV" . "Bouvet Island") + ("BW" . "Botswana") + ("BY" . "Belarus") + ("BZ" . "Belize") + ("CA" . "Canada") + ("CC" . "Cocos (Keeling) Islands") + ("CD" . "Democratic Republic of the Congo") + ("CF" . "Central African Republic") + ("CG" . "Republic of the Congo") + ("CH" . "Switzerland") + ("CI" . "Cýte d'Ivoire") + ("CK" . "Cook Islands") + ("CL" . "Chile") + ("CM" . "Cameroon") + ("CN" . "China") + ("CO" . "Colombia") + ("CR" . "Costa Rica") + ("CU" . "Cuba") + ("CV" . "Cape Verde") + ("CX" . "Christmas Island") + ("CY" . "Cyprus") + ("CZ" . "Czech Republic") + ("DE" . "Germany") + ("DJ" . "Djibouti") + ("DK" . "Denmark") + ("DM" . "Dominica") + ("DO" . "Dominican Republic") + ("DZ" . "Algeria") + ("EC" . "Ecuador") + ("EE" . "Estonia") + ("EG" . "Egypt") + ("EH" . "Western Sahara") + ("ER" . "Eritrea") + ("ES" . "Spain") + ("ET" . "Ethiopia") + ("FI" . "Finland") + ("FJ" . "Fiji") + ("FK" . "Falkland Islands") + ("FM" . "Federated States of Micronesia") + ("FO" . "Faroe Islands") + ("FR" . "France") + ("GA" . "Gabon") + ("GB" . "United Kingdom") + ("GD" . "Grenada") + ("GE" . "Georgia") + ("GF" . "French Guiana") + ("GG" . "Guernsey") + ("GH" . "Ghana") + ("GI" . "Gibraltar") + ("GL" . "Greenland") + ("GM" . "Gambia") + ("GN" . "Guinea") + ("GP" . "Guadeloupe") + ("GQ" . "Equatorial Guinea") + ("GR" . "Greece") + ("GS" . "South Georgia and the South Sandwich Islands") + ("GT" . "Guatemala") + ("GU" . "Guam") + ("GW" . "Guinea-Bissau") + ("GY" . "Guyana") + ("HK" . "Hong Kong") + ("HM" . "Heard Island and McDonald Islands") + ("HN" . "Honduras") + ("HR" . "Croatia") + ("HT" . "Haiti") + ("HU" . "Hungary") + ("ID" . "Indonesia") + ("IE" . "Ireland") + ("IL" . "Israel") + ("IM" . "Isle of Man") + ("IN" . "India") + ("IO" . "British Indian Ocean Territory") + ("IQ" . "Iraq") + ("IR" . "Iran") + ("IS" . "Iceland") + ("IT" . "Italy") + ("JE" . "Jersey") + ("JM" . "Jamaica") + ("JO" . "Jordan") + ("JP" . "Japan") + ("KE" . "Kenya") + ("KG" . "Kyrgyzstan") + ("KH" . "Cambodia") + ("KI" . "Kiribati") + ("KM" . "Comoros") + ("KN" . "Saint Kitts and Nevis") + ("KP" . "North Korea") + ("KR" . "South Korea") + ("KW" . "Kuwait") + ("KY" . "Cayman Islands") + ("KZ" . "Kazakhstan") + ("LA" . "Laos") + ("LB" . "Lebanon") + ("LC" . "Saint Lucia") + ("LI" . "Liechtenstein") + ("LK" . "Sri Lanka") + ("LR" . "Liberia") + ("LS" . "Lesotho") + ("LT" . "Lithuania") + ("LU" . "Luxembourg") + ("LV" . "Latvia") + ("LY" . "Libya") + ("MA" . "Morocco") + ("MC" . "Monaco") + ("MD" . "Moldova") + ("ME" . "Montenegro") + ("MF" . "Saint Martin") + ("MG" . "Madagascar") + ("MH" . "Marshall Islands") + ("MK" . "Macedonia") + ("ML" . "Mali") + ("MM" . "Burma/Myanmar") + ("MN" . "Mongolia") + ("MO" . "Macao") + ("MP" . "Northern Mariana Islands") + ("MQ" . "Martinique") + ("MR" . "Mauritania") + ("MS" . "Montserrat") + ("MT" . "Malta") + ("MU" . "Mauritius") + ("MV" . "Maldives") + ("MW" . "Malawi") + ("MX" . "Mexico") + ("MY" . "Malaysia") + ("MZ" . "Mozambique") + ("NA" . "Namibia") + ("NC" . "New Caledonia") + ("NE" . "Niger") + ("NF" . "Norfolk Island") + ("NG" . "Nigeria") + ("NI" . "Nicaragua") + ("NL" . "Netherlands") + ("NO" . "Norway") + ("NP" . "Nepal") + ("NR" . "Nauru") + ("NU" . "Niue") + ("NZ" . "New Zealand") + ("OM" . "Oman") + ("PA" . "Panama") + ("PE" . "Peru") + ("PF" . "French Polynesia") + ("PG" . "Papua New Guinea") + ("PH" . "Philippines") + ("PK" . "Pakistan") + ("PL" . "Poland") + ("PM" . "Saint Pierre and Miquelon") + ("PN" . "Pitcairn Islands") + ("PR" . "Puerto Rico") + ("PS" . "Palestinian territories") + ("PT" . "Portugal") + ("PW" . "Palau") + ("PY" . "Paraguay") + ("QA" . "Qatar") + ("RE" . "Rýunion") + ("RO" . "Romania") + ("RS" . "Serbia") + ("RU" . "Russia") + ("RW" . "Rwanda") + ("SA" . "Saudi Arabia") + ("SB" . "Solomon Islands") + ("SC" . "Seychelles") + ("SD" . "Sudan") + ("SE" . "Sweden") + ("SG" . "Singapore") + ("SH" . "Saint Helena") + ("SI" . "Slovenia") + ("SJ" . "Svalbard and Jan Mayen") + ("SK" . "Slovakia") + ("SL" . "Sierra Leone") + ("SM" . "San Marino") + ("SN" . "Senegal") + ("SO" . "Somalia") + ("SR" . "Suriname") + ("ST" . "Sýo Tomý and Prýncipe") + ("SV" . "El Salvador") + ("SY" . "Syria") + ("SZ" . "Swaziland") + ("TC" . "Turks and Caicos Islands") + ("TD" . "Chad") + ("TF" . "French Southern Territories") + ("TG" . "Togo") + ("TH" . "Thailand") + ("TJ" . "Tajikistan") + ("TK" . "Tokelau") + ("TL" . "East Timor") + ("TM" . "Turkmenistan") + ("TN" . "Tunisia") + ("TO" . "Tonga") + ("TR" . "Turkey") + ("TT" . "Trinidad and Tobago") + ("TV" . "Tuvalu") + ("TW" . "Taiwan") + ("TZ" . "Tanzania") + ("UA" . "Ukraine") + ("UG" . "Uganda") + ("UM" . "United States Minor Outlying Islands") + ("US" . "United States") + ("UY" . "Uruguay") + ("UZ" . "Uzbekistan") + ("VA" . "Vatican City State") + ("VC" . "Saint Vincent and the Grenadines") + ("VE" . "Venezuela") + ("VG" . "British Virgin Islands") + ("VI" . "Virgin Islands, U.S.") + ("VN" . "Vietnam") + ("VU" . "Vanuatu") + ("WF" . "Wallis and Futuna") + ("WS" . "Samoa") + ("YE" . "Yemen") + ("YT" . "Mayotte") + ("ZA" . "South Africa") + ("ZM" . "Zambia") + ("ZW" . "Zimbabwe") + + ("AC" . "Ascension Island") + ("CP" . "Clipperton Island") + ("DG" . "Diego Garcia") + ("EA" . "Ceuta") + ("EU" . "European Union") + ("FX" . "Metropolitan France") + ("IC" . "Canary Islands") + ("SU" . "Soviet Union") + ("TA" . "Tristan da Cunha") + ("UK" . "United Kingdom") + + ("BU" . "Burma") + ("CS" . "Serbia and Montenegro") + ("NT" . "Saudi-Iraqi neutral zone") + ("SF" . "Finland") + ("TP" . "East Timor") + ("YU" . "Yugoslavia") + ("ZR" . "Zaire") + + ("DY" . "Benin") + ("EW" . "Estonia") + ("FL" . "Liechtenstein") + ("JA" . "Jamaica") + ("LF" . "Libya Fezzan") + ("PI" . "Philippines") + ("RA" . "Argentina") + ("RB" . "Bolivia") + ("RC" . "China") + ("RH" . "Haiti") + ("RI" . "Indonesia") + ("RL" . "Lebanon") + ("RM" . "Madagascar") + ("RN" . "Niger") + ("RP" . "Philippines") + ("WG" . "Grenada") + ("WL" . "Saint Lucia") + ("WV" . "Saint Vincent and the Grenadines") + ("YV" . "Venezuela"))) + +(defun rw-lacc-get-language (language-code) + "Get language code from string, e. g. \"en\"." + (if (string-match "^[a-z][a-z][a-z]?$" language-code) + (downcase (or (cdr (assoc-string language-code + rw-lacc-language-codes)) + language-code)) + language-code)) + +(defun rw-lacc-get-country (country-code) + "Get country code from string, e. g. \"US\"." + (if (string-match "^[A-Z][A-Z][A-Z]?$" country-code) + (or (cdr (assoc-string country-code + rw-lacc-country-codes)) + country-code) + country-code)) + +(defun rw-lacc-get-language-and-country (language-and-country-code) + "Get language and country code from string, e. g. \"en_US\" or \"en-US\"." + (if (string-match "\\(^[a-z][a-z][a-z]?\\)\\([_-]\\)\\([A-Z][A-Z][A-Z]?\\)$" + language-and-country-code) + (let ((language (match-string 1 language-and-country-code)) + (separator (match-string 2 language-and-country-code)) + (country (match-string 3 language-and-country-code))) + (concat (rw-lacc-get-language language) + separator + (rw-lacc-get-country country))) + language-and-country-code)) + +(defun rw-lacc-replace-code-in-string (string) + "Replace language and country code in STRING, +e. g. \"en_US\" to \"english_United States\". +Return a new string containing the replacements." + (replace-regexp-in-string + "[a-z][a-z][a-z]?[_-][A-Z][A-Z][A-Z]?" + '(lambda (str) + (save-match-data (rw-lacc-get-language-and-country str))) + string)) + +(provide 'rw-language-and-country-codes) + +;;; rw-language-and-country-codes.el ends here. diff --git a/lisp/tabbar.el b/lisp/tabbar.el new file mode 100644 index 0000000..1d33513 --- /dev/null +++ b/lisp/tabbar.el @@ -0,0 +1,1937 @@ +;;; Tabbar.el --- Display a tab bar in the header line + +;; Copyright (C) 2003, 2004, 2005 David Ponce + +;; Author: David Ponce +;; Maintainer: David Ponce +;; Created: 25 February 2003 +;; Keywords: convenience +;; Revision: $Id: tabbar.el,v 1.7 2010/11/22 23:30 m00natic Exp $ + +(defconst tabbar-version "2.0") + +;; This file is not part of GNU Emacs. + +;; 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, 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; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. + +;;; Commentary: +;; +;; This library provides the Tabbar global minor mode to display a tab +;; bar in the header line of Emacs 21 and later versions. You can use +;; the mouse to click on a tab and select it. Also, three buttons are +;; displayed on the left side of the tab bar in this order: the +;; "home", "scroll left", and "scroll right" buttons. The "home" +;; button is a general purpose button used to change something on the +;; tab bar. The scroll left and scroll right buttons are used to +;; scroll tabs horizontally. Tabs can be divided up into groups to +;; maintain several sets of tabs at the same time (see also the +;; chapter "Core" below for more details on tab grouping). Only one +;; group is displayed on the tab bar, and the "home" button, for +;; example, can be used to navigate through the different groups, to +;; show different tab bars. +;; +;; In a graphic environment, using the mouse is probably the preferred +;; way to work with the tab bar. However, you can also use the tab +;; bar when Emacs is running on a terminal, so it is possible to use +;; commands to press special buttons, or to navigate cyclically +;; through tabs. +;; +;; These commands, and default keyboard shortcuts, are provided: +;; +;; `tabbar-mode' +;; Toggle the Tabbar global minor mode. When enabled a tab bar is +;; displayed in the header line. +;; +;; `tabbar-local-mode' (C-c ) +;; Toggle the Tabbar-Local minor mode. Provided the global minor +;; mode is turned on, the tab bar becomes local in the current +;; buffer when the local minor mode is enabled. This permits to +;; see the tab bar in a buffer where the header line is already +;; used by another mode (like `Info-mode' for example). +;; +;; `tabbar-mwheel-mode' +;; Toggle the Tabbar-Mwheel global minor mode. When enabled you +;; can use the mouse wheel to navigate through tabs of groups. +;; +;; `tabbar-press-home' (C-c ) +;; `tabbar-press-scroll-left' (C-c ) +;; `tabbar-press-scroll-right' (C-c ) +;; Simulate a mouse-1 click on respectively the "home", "scroll +;; left", and "scroll right" buttons. A numeric prefix argument +;; value of 2, or 3, respectively simulates a mouse-2, or mouse-3 +;; click. +;; +;; `tabbar-backward' (C-c ) +;; `tabbar-forward' (C-c ) +;; Are the basic commands to navigate cyclically through tabs or +;; groups of tabs. The cycle is controlled by the +;; `tabbar-cycle-scope' option. The default is to navigate +;; through all tabs across all existing groups of tabs. You can +;; change the default behavior to navigate only through the tabs +;; visible on the tab bar, or through groups of tabs only. Or use +;; the more specialized commands below. +;; +;; `tabbar-backward-tab' +;; `tabbar-forward-tab' +;; Navigate through the tabs visible on the tab bar. +;; +;; `tabbar-backward-group' (C-c ) +;; `tabbar-forward-group' (C-c ) +;; Navigate through existing groups of tabs. +;; +;; +;; Core +;; ---- +;; +;; The content of the tab bar is represented by an internal data +;; structure: a tab set. A tab set is a collection (group) of tabs, +;; identified by an unique name. In a tab set, at any time, one and +;; only one tab is designated as selected within the tab set. +;; +;; A tab is a simple data structure giving the value of the tab, and a +;; reference to its tab set container. A tab value can be any Lisp +;; object. Each tab object is guaranteed to be unique. +;; +;; A tab set is displayed on the tab bar through a "view" defined by +;; the index of the leftmost tab shown. Thus, it is possible to +;; scroll the tab bar horizontally by changing the start index of the +;; tab set view. +;; +;; The visual representation of a tab bar is a list of valid +;; `header-line-format' template elements, one for each special +;; button, and for each tab found into a tab set "view". When the +;; visual representation of a tab is required, the function specified +;; in the variable `tabbar-tab-label-function' is called to obtain it. +;; The visual representation of a special button is obtained by +;; calling the function specified in `tabbar-button-label-function', +;; which is passed a button name among `home', `scroll-left', or +;; `scroll-right'. There are also options and faces to customize the +;; appearance of buttons and tabs (see the code for more details). +;; +;; When the mouse is over a tab, the function specified in +;; `tabbar-help-on-tab-function' is called, which is passed the tab +;; and should return a help string to display. When a tab is +;; selected, the function specified in `tabbar-select-tab-function' is +;; called, which is passed the tab and the event received. +;; +;; Similarly, to control the behavior of the special buttons, the +;; following variables are available, for respectively the `home', +;; `scroll-left' and `scroll-right' value of `