├── .gitignore ├── .travis.yml ├── Makefile ├── README.markdown ├── ert-tests ├── examples │ ├── CVS │ │ ├── bash-fc-0 │ │ ├── elisp_protpath_localnil.el │ │ ├── elisp_protpath_localt.el │ │ ├── text_protpath.txt │ │ └── text_protpath_editpat.txt │ ├── editpat-autoloads.el │ ├── elisp_editpat.el │ ├── elisp_editpat_localnil.el │ ├── elisp_editpat_localt.el │ ├── elisp_editpat_readonlyfile.el │ ├── elisp_nopat.bak │ ├── elisp_nopat.el │ ├── elisp_protpat.el │ ├── elisp_protpat_editpat.el │ ├── elisp_protpat_localnil.el │ ├── elisp_protpat_localt.el │ ├── perl_endpat.pl │ ├── perl_endpat_semantic.pl │ ├── perl_endpat_toofar.pl │ ├── perl_modepat.pl │ ├── protected-autoloads.el │ ├── shell-editpat.sh │ └── text_perlmodepat.txt └── hardhat-test.el └── hardhat.el /.gitignore: -------------------------------------------------------------------------------- 1 | /ert-tests/ert.el 2 | /ert-tests/ignoramus.el 3 | *-autoloads.el 4 | *.elc 5 | *~ 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | ### 2 | ### Notes 3 | ### 4 | ### The travis web interface may choke silently and fail to 5 | ### update when there are issues with the .travis.yml file. 6 | ### 7 | ### The "travis-lint" command-line tool does not catch all 8 | ### errors which may lead to silent failure. 9 | ### 10 | ### Shell-style comments must have "#" as the first character 11 | ### of the line. 12 | ### 13 | 14 | ### 15 | ### language 16 | ### 17 | 18 | # travis-lint no longer permits this value 19 | # language: emacs-lisp 20 | language: ruby 21 | 22 | ### 23 | ### defining the build matrix 24 | ### 25 | ### ===> <=== 26 | ### ===> each variation in env/matrix will be built and tested <=== 27 | ### ===> <=== 28 | ### 29 | ### variables under env/global are available to the build process 30 | ### but don't cause the creation of a separate variation 31 | ### 32 | 33 | env: 34 | matrix: 35 | - EMACS=emacs22 36 | - EMACS=emacs23 37 | - EMACS=emacs24 38 | - EMACS=emacs-snapshot 39 | global: 40 | - SOME_TOKEN=some_value 41 | 42 | ### 43 | ### allowing failures 44 | ### 45 | 46 | matrix: 47 | allow_failures: 48 | - env: EMACS=emacs22 49 | - env: EMACS=emacs-snapshot 50 | 51 | ### 52 | ### limit build attempts to defined branches 53 | ### 54 | 55 | # branches: 56 | # only: 57 | # - master 58 | 59 | ### 60 | ### runtime initialization 61 | ### 62 | ### notes 63 | ### 64 | ### emacs22 is extracted manually from Ubuntu Maverick. 65 | ### 66 | ### emacs23 is the stock default, but is updated anyway to 67 | ### a GUI-capable version, which will have certain additional 68 | ### functions compiled in. 69 | ### 70 | ### emacs24 (current stable release) is obtained from the 71 | ### cassou PPA: http://launchpad.net/~cassou/+archive/emacs 72 | ### 73 | ### emacs-snapshot (trunk) is obtained from the Ubuntu Emacs Lisp PPA: 74 | ### https://launchpad.net/~ubuntu-elisp/+archive/ppa 75 | ### For the emacs-snapshot build, bleeding-edge versions 76 | ### of all test dependencies are also used. 77 | ### 78 | 79 | before_install: 80 | - git submodule --quiet update --init --recursive 81 | 82 | install: 83 | - if [ "$EMACS" = 'emacs22' ]; then 84 | curl -Os http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22_22.2-0ubuntu9_i386.deb && 85 | curl -Os http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22-bin-common_22.2-0ubuntu9_i386.deb && 86 | curl -Os http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22-common_22.2-0ubuntu9_all.deb && 87 | curl -Os http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22-el_22.2-0ubuntu9_all.deb && 88 | curl -Os http://security.ubuntu.com/ubuntu/pool/universe/e/emacs22/emacs22-gtk_22.2-0ubuntu9_i386.deb && 89 | sudo apt-get -qq update && 90 | sudo apt-get -qq remove emacs emacs23-bin-common emacs23-common emacs23-nox && 91 | sudo apt-get -qq --fix-missing install install-info emacsen-common libjpeg62:i386 xaw3dg:i386 liblockfile1:i386 libasound2:i386 libgif4:i386 libncurses5:i386 libpng12-0:i386 libtiff4:i386 libxpm4:i386 libxft2:i386 libglib2.0-0:i386 libgtk2.0-0:i386 && 92 | sudo apt-get -qq -f install && 93 | sudo dpkg -i emacs22-common_22.2-0ubuntu9_all.deb emacs22-el_22.2-0ubuntu9_all.deb && 94 | sudo dpkg -i --force-depends emacs22-bin-common_22.2-0ubuntu9_i386.deb && 95 | sudo dpkg -i emacs22_22.2-0ubuntu9_i386.deb emacs22-gtk_22.2-0ubuntu9_i386.deb && 96 | sudo update-alternatives --set emacs22 /usr/bin/emacs22-gtk; 97 | fi 98 | - if [ "$EMACS" = 'emacs23' ]; then 99 | sudo apt-get -qq update && 100 | sudo apt-get -qq -f install && 101 | sudo apt-get -qq install emacs23-gtk emacs23-el; 102 | fi 103 | - if [ "$EMACS" = 'emacs24' ]; then 104 | sudo add-apt-repository -y ppa:cassou/emacs && 105 | sudo apt-get -qq update && 106 | sudo apt-get -qq -f install && 107 | sudo apt-get -qq install emacs24 emacs24-el; 108 | fi 109 | - if [ "$EMACS" = 'emacs-snapshot' ]; then 110 | sudo add-apt-repository -y ppa:ubuntu-elisp/ppa && 111 | sudo apt-get -qq update && 112 | sudo apt-get -qq -f install && 113 | sudo apt-get -qq install emacs-snapshot && 114 | sudo apt-get -qq install emacs-snapshot-el; 115 | fi 116 | 117 | before_script: 118 | - if [ "$EMACS" = 'emacs-snapshot' ]; then 119 | make downloads-latest; 120 | else 121 | make downloads; 122 | fi 123 | 124 | ### 125 | ### the actual build/test command 126 | ### 127 | 128 | script: 129 | $EMACS --version && ( test "$EMACS" != "emacs22" && make test EMACS="$EMACS" || make test-batch EMACS="$EMACS" ) 130 | 131 | ### 132 | ### settings 133 | ### 134 | 135 | notifications: 136 | email: false 137 | 138 | # 139 | # Emacs 140 | # 141 | # Local Variables: 142 | # indent-tabs-mode: nil 143 | # mangle-whitespace: t 144 | # require-final-newline: t 145 | # coding: utf-8 146 | # End: 147 | # 148 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | EMACS=emacs 2 | # EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs 3 | # EMACS=/Applications/Emacs23.app/Contents/MacOS/Emacs 4 | # EMACS=/Applications/Aquamacs.app/Contents/MacOS/Aquamacs 5 | # EMACS=/Applications/Macmacs.app/Contents/MacOS/Emacs 6 | # EMACS=/usr/local/bin/emacs 7 | # EMACS=/opt/local/bin/emacs 8 | # EMACS=/usr/bin/emacs 9 | 10 | INTERACTIVE_EMACS=/usr/local/bin/emacs 11 | # can't find an OS X variant that works correctly for interactive tests: 12 | # INTERACTIVE_EMACS=open -a Emacs.app --new --args 13 | # INTERACTIVE_EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs 14 | # INTERACTIVE_EMACS=/Applications/Emacs.app/Contents/MacOS/bin/emacs 15 | 16 | RESOLVED_EMACS=$(shell readlink `which $(EMACS)` || echo "$(EMACS)") 17 | RESOLVED_INTERACTIVE_EMACS=$(shell readlink `which "$(INTERACTIVE_EMACS)"` || echo "$(INTERACTIVE_EMACS)") 18 | 19 | EMACS_CLEAN=-Q 20 | EMACS_BATCH=$(EMACS_CLEAN) --batch 21 | # TESTS can be overridden to specify a subset of tests 22 | TESTS= 23 | WIKI_USERNAME=roland.walker 24 | 25 | CURL=curl --location --silent 26 | EDITOR=runemacs -no_wait 27 | WORK_DIR=$(shell pwd) 28 | PACKAGE_NAME=$(shell basename $(WORK_DIR)) 29 | PACKAGE_VERSION=$(shell perl -ne 'print "$$1\n" if m{^;+ *Version: *(\S+)}' $(PACKAGE_NAME).el) 30 | AUTOLOADS_FILE=$(PACKAGE_NAME)-autoloads.el 31 | TRAVIS_FILE=.travis.yml 32 | TEST_DIR=ert-tests 33 | TEST_DEP_1=ert 34 | TEST_DEP_1_STABLE_URL=http://git.savannah.gnu.org/cgit/emacs.git/plain/lisp/emacs-lisp/ert.el?h=emacs-24.3 35 | TEST_DEP_1_LATEST_URL=http://git.savannah.gnu.org/cgit/emacs.git/plain/lisp/emacs-lisp/ert.el?h=master 36 | TEST_DEP_2=ignoramus 37 | TEST_DEP_2_STABLE_URL=https://raw.githubusercontent.com/rolandwalker/ignoramus/37536286eb1da6d7bb9590e039485c456fdfd245/ignoramus.el 38 | TEST_DEP_2_LATEST_URL=https://raw.githubusercontent.com/rolandwalker/ignoramus/master/ignoramus.el 39 | 40 | .PHONY : build dist not-dirty pkg-version downloads downloads-latest autoloads \ 41 | test-autoloads test-travis test test-prep test-batch test-interactive \ 42 | test-tests clean edit run-pristine run-pristine-local upload-github \ 43 | upload-wiki upload-marmalade test-dep-1 test-dep-2 test-dep-3 test-dep-4 \ 44 | test-dep-5 test-dep-6 test-dep-7 test-dep-8 test-dep-9 45 | 46 | build : 47 | $(RESOLVED_EMACS) $(EMACS_BATCH) --eval \ 48 | "(progn \ 49 | (setq byte-compile-error-on-warn t) \ 50 | (batch-byte-compile))" *.el 51 | 52 | not-dirty : 53 | @git diff --quiet '$(PACKAGE_NAME).el' || \ 54 | ( git --no-pager diff '$(PACKAGE_NAME).el'; \ 55 | echo "Uncommitted edits - do a git stash"; \ 56 | false ) 57 | 58 | pkg-version : 59 | @test -n '$(PACKAGE_VERSION)' || \ 60 | ( echo "No package version"; false ) 61 | 62 | test-dep-1 : 63 | @cd '$(TEST_DIR)' && \ 64 | $(RESOLVED_EMACS) $(EMACS_BATCH) -L . -L .. -l '$(TEST_DEP_1)' || \ 65 | (echo "Can't load test dependency $(TEST_DEP_1).el, run 'make downloads' to fetch it" ; exit 1) 66 | 67 | test-dep-2 : 68 | @cd '$(TEST_DIR)' && \ 69 | $(RESOLVED_EMACS) $(EMACS_BATCH) -L . -L .. --eval \ 70 | "(progn \ 71 | (setq package-load-list '(($(TEST_DEP_2) t))) \ 72 | (when (fboundp 'package-initialize) \ 73 | (package-initialize)) \ 74 | (require '$(TEST_DEP_2)))" || \ 75 | (echo "Can't load test dependency $(TEST_DEP_2).el, run 'make downloads' to fetch it" ; exit 1) 76 | 77 | downloads : 78 | $(CURL) '$(TEST_DEP_1_STABLE_URL)' > '$(TEST_DIR)/$(TEST_DEP_1).el' 79 | $(CURL) '$(TEST_DEP_2_STABLE_URL)' > '$(TEST_DIR)/$(TEST_DEP_2).el' 80 | 81 | downloads-latest : 82 | $(CURL) '$(TEST_DEP_1_LATEST_URL)' > '$(TEST_DIR)/$(TEST_DEP_1).el' 83 | $(CURL) '$(TEST_DEP_2_LATEST_URL)' > '$(TEST_DIR)/$(TEST_DEP_2).el' 84 | 85 | autoloads : 86 | $(RESOLVED_EMACS) $(EMACS_BATCH) --eval \ 87 | "(progn \ 88 | (setq generated-autoload-file \"$(WORK_DIR)/$(AUTOLOADS_FILE)\") \ 89 | (update-directory-autoloads \"$(WORK_DIR)\"))" 90 | 91 | test-autoloads : autoloads 92 | @$(RESOLVED_EMACS) $(EMACS_BATCH) -L . -l './$(AUTOLOADS_FILE)' || \ 93 | ( echo "failed to load autoloads: $(AUTOLOADS_FILE)" && false ) 94 | 95 | test-travis : 96 | @if test -z "$$TRAVIS" && test -e '$(TRAVIS_FILE)'; then travis-lint '$(TRAVIS_FILE)'; fi 97 | 98 | test-tests : 99 | @perl -ne 'if (m/^\s*\(\s*ert-deftest\s*(\S+)/) {die "$$1 test name duplicated in $$ARGV\n" if $$dupes{$$1}++}' '$(TEST_DIR)/'*-test.el 100 | 101 | test-prep : build test-dep-1 test-autoloads test-travis test-tests 102 | 103 | test-batch : 104 | @cd '$(TEST_DIR)' && \ 105 | (for test_lib in *-test.el; do \ 106 | $(RESOLVED_EMACS) $(EMACS_BATCH) -L . -L .. -l cl \ 107 | -l '$(TEST_DEP_1)' -l "$$test_lib" --eval \ 108 | "(progn \ 109 | (fset 'ert--print-backtrace 'ignore) \ 110 | (ert-run-tests-batch-and-exit '(and \"$(TESTS)\" (not (tag :interactive)))))" || exit 1; \ 111 | done) 112 | 113 | test-interactive : test-prep 114 | @cd '$(TEST_DIR)' && \ 115 | (for test_lib in *-test.el; do \ 116 | $(RESOLVED_INTERACTIVE_EMACS) $(EMACS_CLEAN) --eval \ 117 | "(progn \ 118 | (cd \"$(WORK_DIR)/$(TEST_DIR)\") \ 119 | (setq dired-use-ls-dired nil) \ 120 | (setq frame-title-format \"TEST SESSION $$test_lib\") \ 121 | (setq enable-local-variables :safe))" \ 122 | -L . -L .. -l cl -l '$(TEST_DEP_1)' -l "$$test_lib" \ 123 | --visit "$$test_lib" --eval \ 124 | "(progn \ 125 | (when (> (length \"$(TESTS)\") 0) \ 126 | (push \"\\\"$(TESTS)\\\"\" ert--selector-history)) \ 127 | (setq buffer-read-only t) \ 128 | (setq cursor-in-echo-area t) \ 129 | (call-interactively 'ert-run-tests-interactively) \ 130 | (ding) \ 131 | (when (y-or-n-p \"PRESS Y TO QUIT THIS TEST SESSION\") \ 132 | (with-current-buffer \"*ert*\" \ 133 | (kill-emacs \ 134 | (if (re-search-forward \"^Failed:[^\\n]+unexpected\" 500 t) 1 0)))))" || exit 1; \ 135 | done) 136 | 137 | test : test-prep test-batch 138 | 139 | run-pristine : 140 | @cd '$(TEST_DIR)' && \ 141 | $(RESOLVED_EMACS) $(EMACS_CLEAN) --eval \ 142 | "(progn \ 143 | (setq package-enable-at-startup nil) \ 144 | (setq package-load-list nil) \ 145 | (when (fboundp 'package-initialize) \ 146 | (package-initialize)) \ 147 | (cd \"$(WORK_DIR)/$(TEST_DIR)\") \ 148 | (setq dired-use-ls-dired nil) \ 149 | (setq frame-title-format \"PRISTINE SESSION $(PACKAGE_NAME)\") \ 150 | (setq enable-local-variables :safe))" \ 151 | -L .. -l '$(PACKAGE_NAME)' . 152 | 153 | run-pristine-local : 154 | @cd '$(TEST_DIR)' && \ 155 | $(RESOLVED_EMACS) $(EMACS_CLEAN) --eval \ 156 | "(progn \ 157 | (cd \"$(WORK_DIR)/$(TEST_DIR)\") \ 158 | (setq dired-use-ls-dired nil) \ 159 | (setq frame-title-format \"PRISTINE-LOCAL SESSION $(PACKAGE_NAME)\") \ 160 | (setq enable-local-variables :safe))" \ 161 | -L . -L .. -l '$(PACKAGE_NAME)' . 162 | 163 | clean : 164 | @rm -f '$(AUTOLOADS_FILE)' *.elc *~ */*.elc */*~ .DS_Store */.DS_Store *.bak */*.bak && \ 165 | cd '$(TEST_DIR)' && \ 166 | rm -f './$(TEST_DEP_1).el' './$(TEST_DEP_2).el' './$(TEST_DEP_3).el' './$(TEST_DEP_4).el' './$(TEST_DEP_5a).el' \ 167 | './$(TEST_DEP_5).el' './$(TEST_DEP_6).el' './$(TEST_DEP_7).el' './$(TEST_DEP_8).el' './$(TEST_DEP_9).el' 168 | 169 | edit : 170 | @$(EDITOR) `git ls-files` 171 | 172 | upload-github : 173 | @git push origin master 174 | 175 | upload-marmalade : 176 | @marmalade-upload roland.walker '$(PACKAGE_NAME).el' 177 | 178 | upload-wiki : not-dirty 179 | @$(RESOLVED_EMACS) $(EMACS_BATCH) --eval \ 180 | "(progn \ 181 | (setq package-load-list '((yaoddmuse t))) \ 182 | (when (fboundp 'package-initialize) \ 183 | (package-initialize)) \ 184 | (require 'yaoddmuse) \ 185 | (setq yaoddmuse-username \"$(WIKI_USERNAME)\") \ 186 | (yaoddmuse-post-file \ 187 | \"$(PACKAGE_NAME).el\" \ 188 | yaoddmuse-default-wiki \ 189 | \"$(PACKAGE_NAME).el\" \ 190 | \"updated version\") \ 191 | (sleep-for 5))" 192 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | [![Build Status](https://secure.travis-ci.org/rolandwalker/hardhat.png?branch=master)](http://travis-ci.org/rolandwalker/hardhat) 2 | 3 | # Overview 4 | 5 | Protect against clobbering user-writable files in Emacs. 6 | 7 | * [Quickstart](#quickstart) 8 | * [Explanation](#explanation) 9 | * [See Also](#see-also) 10 | * [Notes](#notes) 11 | * [Compatibility and Requirements](#compatibility-and-requirements) 12 | * [Prior art](#prior-art) 13 | * [Bugs](#bugs) 14 | 15 | ## Quickstart 16 | 17 | ```elisp 18 | (require 'hardhat) 19 | 20 | (global-hardhat-mode 1) 21 | 22 | ;; now you are protected from editing: 23 | ;; 24 | ;; .git/index 25 | ;; ~/.emacs.d/elpa/hardhat-0.1.0/hardhat.el 26 | ;; ~/.emacs~ 27 | ;; 28 | ;; and many others 29 | ``` 30 | 31 | ## Explanation 32 | 33 | A recent unwholesome trend is for package managers to install files 34 | in locations such as `~/.cabal/`, `~/.rvm/`, or `~/.emacs.d/elpa/`. 35 | It is rarely meant for such files to be edited; doing so can cause 36 | data loss in some circumstances. 37 | 38 | In addition, many user-writable files created in the course of 39 | ordinary work should never be altered by a text editor, *eg* the 40 | database stored in a `.git` directory. 41 | 42 | `hardhat.el` provides an extra layer of protection in your work. If 43 | you visit a file which looks unsafe to edit, Emacs will make the 44 | buffer read-only -- even when the underlying file is writable. 45 | 46 | The read-only protection can be turned off for a buffer by the 47 | usual methods, or by toggling off buffer-local `hardhat-mode` via 48 | the lighter menu or 49 | 50 | M-x hardhat-mode RET 51 | 52 | If a buffer is not visiting a file, `hardhat-mode` has no effect. 53 | If the visited file is not writable by the user, `hardhat-mode` 54 | has no effect. 55 | 56 | To use hardhat, place the `hardhat.el` library somewhere 57 | Emacs can find it, and add the following to your `~/.emacs` file: 58 | 59 | ```elisp 60 | (require 'hardhat) 61 | (global-hardhat-mode 1) 62 | ``` 63 | 64 | To inquire as to why hardhat has set or unset protection in 65 | a buffer, the following interactive command is provided 66 | 67 | hardhat-status 68 | 69 | but not bound to any key. 70 | 71 | ## See Also 72 | 73 | * M-x customize-group RET hardhat RET 74 | 75 | ## Notes 76 | 77 | `hardhat-mode` takes no action until the user attempts an 78 | interactive command in a buffer. This is (out of an abundance 79 | of caution) for compatibility: an Emacs Lisp library may freely 80 | open and write to a file protected by `hardhat-mode`, so long as 81 | it is done programatically. 82 | 83 | For any of the options settable in `customize`, rules making 84 | buffers "editable" override rules making buffers "protected". 85 | 86 | A Boolean file-local variable `hardhat-protect` is provided. 87 | When `hardhat-protect` is set to either t or nil, no other 88 | rules are consulted. 89 | 90 | Regular-expression matches are case-insensitive. A case- 91 | sensitive test can be implemented by adding custom function 92 | to eg `hardhat-buffer-protected-functions`. 93 | 94 | ## Compatibility and Requirements 95 | 96 | GNU Emacs version 25.1-devel : not tested 97 | GNU Emacs version 24.5 : not tested 98 | GNU Emacs version 24.4 : yes 99 | GNU Emacs version 24.3 : yes 100 | GNU Emacs version 23.3 : yes 101 | GNU Emacs version 22.2 : yes, with some limitations 102 | GNU Emacs version 21.x and lower : unknown 103 | 104 | Uses if present: [ignoramus.el](http://github.com/rolandwalker/ignoramus) 105 | 106 | ## Prior art 107 | 108 | * do-not-edit 109 | 110 | Kevin Ryde 111 | 112 | ## Bugs 113 | 114 | More exceptions are certainly needed in `hardhat-fullpath-editable-regexps`. 115 | 116 | Because Emacs can wedge if `file-truename` is called on a 117 | remote file (eg when using TRAMP), some filename tests used in 118 | hardhat are not precisely equivalent between local and remote 119 | files. You can change this behavior by setting 120 | `hardhat-use-unsafe-remote-truename` via `customize`. A better 121 | solution is to set `find-file-visit-truename` globally. 122 | -------------------------------------------------------------------------------- /ert-tests/examples/CVS/bash-fc-0: -------------------------------------------------------------------------------- 1 | # empty file 2 | -------------------------------------------------------------------------------- /ert-tests/examples/CVS/elisp_protpath_localnil.el: -------------------------------------------------------------------------------- 1 | ;; Local Variables: 2 | ;; hardhat-protect: nil 3 | ;; End: 4 | -------------------------------------------------------------------------------- /ert-tests/examples/CVS/elisp_protpath_localt.el: -------------------------------------------------------------------------------- 1 | ;; Local Variables: 2 | ;; hardhat-protect: t 3 | ;; End: 4 | -------------------------------------------------------------------------------- /ert-tests/examples/CVS/text_protpath.txt: -------------------------------------------------------------------------------- 1 | # empty file 2 | -------------------------------------------------------------------------------- /ert-tests/examples/CVS/text_protpath_editpat.txt: -------------------------------------------------------------------------------- 1 | ;; allow editing this file 2 | -------------------------------------------------------------------------------- /ert-tests/examples/editpat-autoloads.el: -------------------------------------------------------------------------------- 1 | ;; allow editing this file 2 | 3 | (defun tester nil 4 | t) 5 | -------------------------------------------------------------------------------- /ert-tests/examples/elisp_editpat.el: -------------------------------------------------------------------------------- 1 | ;; allow editing this file 2 | 3 | (defun tester nil 4 | t) 5 | -------------------------------------------------------------------------------- /ert-tests/examples/elisp_editpat_localnil.el: -------------------------------------------------------------------------------- 1 | ;; allow editing this file 2 | 3 | (defun tester nil 4 | t) 5 | 6 | ;; Local Variables: 7 | ;; hardhat-protect: nil 8 | ;; End: 9 | -------------------------------------------------------------------------------- /ert-tests/examples/elisp_editpat_localt.el: -------------------------------------------------------------------------------- 1 | ;; allow editing this file 2 | 3 | (defun tester nil 4 | t) 5 | 6 | ;; Local Variables: 7 | ;; hardhat-protect: t 8 | ;; End: 9 | -------------------------------------------------------------------------------- /ert-tests/examples/elisp_editpat_readonlyfile.el: -------------------------------------------------------------------------------- 1 | ;; allow editing this file 2 | 3 | (defun tester nil 4 | t) 5 | -------------------------------------------------------------------------------- /ert-tests/examples/elisp_nopat.bak: -------------------------------------------------------------------------------- 1 | (defun tester nil 2 | t) 3 | -------------------------------------------------------------------------------- /ert-tests/examples/elisp_nopat.el: -------------------------------------------------------------------------------- 1 | (defun tester nil 2 | t) 3 | -------------------------------------------------------------------------------- /ert-tests/examples/elisp_protpat.el: -------------------------------------------------------------------------------- 1 | ;; DO NOT EDIT THIS FILE 2 | 3 | (defun tester nil 4 | t) 5 | -------------------------------------------------------------------------------- /ert-tests/examples/elisp_protpat_editpat.el: -------------------------------------------------------------------------------- 1 | ;; DO NOT EDIT THIS FILE 2 | 3 | ;; allow editing this file 4 | 5 | (defun tester nil 6 | t) 7 | -------------------------------------------------------------------------------- /ert-tests/examples/elisp_protpat_localnil.el: -------------------------------------------------------------------------------- 1 | ;; DO NOT EDIT THIS FILE 2 | 3 | (defun tester nil 4 | t) 5 | 6 | ;; Local Variables: 7 | ;; hardhat-protect: nil 8 | ;; End: 9 | -------------------------------------------------------------------------------- /ert-tests/examples/elisp_protpat_localt.el: -------------------------------------------------------------------------------- 1 | ;; DO NOT EDIT THIS FILE 2 | 3 | (defun tester nil 4 | t) 5 | 6 | ;; Local Variables: 7 | ;; hardhat-protect: t 8 | ;; End: 9 | -------------------------------------------------------------------------------- /ert-tests/examples/perl_endpat.pl: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/perl 2 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 3 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 4 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 5 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 6 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 7 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 8 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 9 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 10 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 11 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 12 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 13 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 14 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 15 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 16 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 17 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 18 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 19 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 20 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 21 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 22 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 23 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 24 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 25 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 26 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 27 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 28 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 29 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 30 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 31 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 32 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 33 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 34 | # protect me 35 | -------------------------------------------------------------------------------- /ert-tests/examples/perl_endpat_semantic.pl: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/perl 2 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 3 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 4 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 5 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 6 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 7 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 8 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 9 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 10 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 11 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 12 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 13 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 14 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 15 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 16 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 17 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 18 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 19 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 20 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 21 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 22 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 23 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 24 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 25 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 26 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 27 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 28 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 29 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 30 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 31 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 32 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 33 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 34 | # protect me 35 | 36 | __DATA__ 37 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 38 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 39 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 40 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 41 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 42 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 43 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 44 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 45 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 46 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 47 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 48 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 49 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 50 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 51 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 52 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 53 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 54 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 55 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 56 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 57 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 58 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 59 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 60 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 61 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 62 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 63 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 64 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 65 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 66 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 67 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 68 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 69 | -------------------------------------------------------------------------------- /ert-tests/examples/perl_endpat_toofar.pl: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/perl 2 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 3 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 4 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 5 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 6 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 7 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 8 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 9 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 10 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 11 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 12 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 13 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 14 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 15 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 16 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 17 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 18 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 19 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 20 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 21 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 22 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 23 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 24 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 25 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 26 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 27 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 28 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 29 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 30 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 31 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 32 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 33 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 34 | # protect me 35 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 36 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 37 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 38 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 39 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 40 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 41 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 42 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 43 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 44 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 45 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 46 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 47 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 48 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 49 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 50 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 51 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 52 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 53 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 54 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 55 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 56 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 57 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 58 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 59 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 60 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 61 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 62 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 63 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 64 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 65 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 66 | # lakjsd flkajs dlfkj asldkjf lkasjd flkj asldkfj laksjd flkja sdlfkj laskdj flkasj dflkj asldkjf lajsd fl 67 | -------------------------------------------------------------------------------- /ert-tests/examples/perl_modepat.pl: -------------------------------------------------------------------------------- 1 | # Changes made here will be lost when autosplit is run again 2 | -------------------------------------------------------------------------------- /ert-tests/examples/protected-autoloads.el: -------------------------------------------------------------------------------- 1 | (defun tester nil 2 | t) 3 | -------------------------------------------------------------------------------- /ert-tests/examples/shell-editpat.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # THIS IS A GENERATED FILE\ 3 | # 4 | -------------------------------------------------------------------------------- /ert-tests/examples/text_perlmodepat.txt: -------------------------------------------------------------------------------- 1 | # Changes made here will be lost when autosplit is run again 2 | -------------------------------------------------------------------------------- /ert-tests/hardhat-test.el: -------------------------------------------------------------------------------- 1 | 2 | ;;; requires and setup 3 | 4 | (when load-file-name 5 | (setq package-enable-at-startup nil) 6 | (setq package-load-list '((ignoramus t))) 7 | (when (fboundp 'package-initialize) 8 | (package-initialize))) 9 | 10 | (require 'ignoramus) 11 | (require 'hardhat) 12 | 13 | 14 | ;;; working-directory 15 | 16 | (ert-deftest hardhat-aaa-working-directory-01 nil 17 | "Check that we are running from the ert-tests directory" 18 | (should 19 | (file-exists-p "./examples/elisp_nopat.el")) 20 | (should 21 | (string-match-p "/ert-tests/\\'" default-directory))) 22 | 23 | 24 | ;;; example files 25 | 26 | (ert-deftest hardhat-example-file-01 nil 27 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 28 | (find-file "./examples/elisp_nopat.el") 29 | (should-not 30 | (hardhat-buffer-included-p (current-buffer))) 31 | (should 32 | (equal nil 33 | hardhat-reasons)) 34 | (kill-buffer (current-buffer)))) 35 | 36 | (ert-deftest hardhat-example-file-02 nil 37 | "cover hardhat-protected-by-ignoramus" 38 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 39 | (find-file "./examples/elisp_nopat.bak") 40 | (should 41 | (hardhat-buffer-included-p (current-buffer))) 42 | (should 43 | (equal (list 'protected 'function 'hardhat-protected-by-ignoramus) 44 | hardhat-reasons)) 45 | (kill-buffer (current-buffer)))) 46 | 47 | (ert-deftest hardhat-example-file-03 nil 48 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 49 | (find-file "./examples/elisp_editpat.el") 50 | (should-not 51 | (hardhat-buffer-included-p (current-buffer))) 52 | (should 53 | (equal (list 'editable 'bof-content ";; allow editing this file") 54 | hardhat-reasons)) 55 | (kill-buffer (current-buffer)))) 56 | 57 | (ert-deftest hardhat-example-file-04 nil 58 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 59 | (find-file "./examples/elisp_editpat_localnil.el") 60 | (hardhat-local-variables-hook) 61 | (should-not 62 | (hardhat-buffer-included-p (current-buffer))) 63 | (should-not 64 | hardhat-mode) 65 | (should 66 | (equal (list 'editable 'file-local-variable nil) 67 | hardhat-reasons)) 68 | (kill-buffer (current-buffer)))) 69 | 70 | (ert-deftest hardhat-example-file-05 nil 71 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 72 | (find-file "./examples/elisp_editpat_localt.el") 73 | (hardhat-local-variables-hook) 74 | (should-not 75 | (hardhat-buffer-included-p (current-buffer))) 76 | (should 77 | hardhat-mode) 78 | (should 79 | (equal (list 'protected 'file-local-variable t) 80 | hardhat-reasons)) 81 | (kill-buffer (current-buffer)))) 82 | 83 | (ert-deftest hardhat-example-file-06 nil 84 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file")) 85 | (file "./examples/elisp_editpat_readonlyfile.el")) 86 | (should 87 | (file-exists-p file)) 88 | (set-file-modes file #o444) 89 | (should-not 90 | (file-writable-p file)) 91 | (find-file file) 92 | (should-not 93 | (hardhat-buffer-included-p (current-buffer))) 94 | (should 95 | (equal nil 96 | hardhat-reasons)) 97 | (kill-buffer (current-buffer)))) 98 | 99 | (ert-deftest hardhat-example-file-07 nil 100 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 101 | (find-file "./examples/elisp_protpat.el") 102 | (should 103 | (hardhat-buffer-included-p (current-buffer))) 104 | (should 105 | (equal (list 'protected 'bof-content "DO NOT EDIT") 106 | hardhat-reasons)) 107 | (kill-buffer (current-buffer)))) 108 | 109 | (ert-deftest hardhat-example-file-08 nil 110 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 111 | (find-file "./examples/elisp_protpat_editpat.el") 112 | (should-not 113 | (hardhat-buffer-included-p (current-buffer))) 114 | (should 115 | (equal (list 'editable 'bof-content ";; allow editing this file") 116 | hardhat-reasons)) 117 | (kill-buffer (current-buffer)))) 118 | 119 | (ert-deftest hardhat-example-file-09 nil 120 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 121 | (find-file "./examples/elisp_protpat_localnil.el") 122 | (hardhat-local-variables-hook) 123 | (should-not 124 | (hardhat-buffer-included-p (current-buffer))) 125 | (should-not 126 | hardhat-mode) 127 | (should 128 | (equal (list 'editable 'file-local-variable nil) 129 | hardhat-reasons)) 130 | (kill-buffer (current-buffer)))) 131 | 132 | (ert-deftest hardhat-example-file-10 nil 133 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 134 | (find-file "./examples/elisp_protpat_localt.el") 135 | (hardhat-local-variables-hook) 136 | (should-not 137 | (hardhat-buffer-included-p (current-buffer))) 138 | (should 139 | hardhat-mode) 140 | (should 141 | (equal (list 'protected 'file-local-variable t) 142 | hardhat-reasons)) 143 | (kill-buffer (current-buffer)))) 144 | 145 | (ert-deftest hardhat-example-file-11 nil 146 | (let ((hardhat-eof-content-protected-regexps '((perl-mode . "protect me") 147 | (cperl-mode . "protect me"))) 148 | (hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 149 | (find-file "./examples/perl_endpat.pl") 150 | (should 151 | (hardhat-buffer-included-p (current-buffer))) 152 | (should 153 | (equal (list 'protected 'eof-content "protect me") 154 | hardhat-reasons)) 155 | (kill-buffer (current-buffer)))) 156 | 157 | (ert-deftest hardhat-example-file-12 nil 158 | "cover hardhat-protected-by-perl-semantic-eof" 159 | (let ((hardhat-eof-content-protected-regexps '((perl-mode . "protect me") 160 | (cperl-mode . "protect me"))) 161 | (hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 162 | (find-file "./examples/perl_endpat_semantic.pl") 163 | (should 164 | (hardhat-buffer-included-p (current-buffer))) 165 | (should 166 | (equal (list 'protected 'function 'hardhat-protected-by-perl-semantic-eof) 167 | hardhat-reasons)) 168 | (kill-buffer (current-buffer)))) 169 | 170 | (ert-deftest hardhat-example-file-13 nil 171 | (let ((hardhat-eof-content-protected-regexps '((perl-mode . "protect me") 172 | (cperl-mode . "protect me"))) 173 | (hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 174 | (find-file "./examples/perl_endpat_toofar.pl") 175 | (should-not 176 | (hardhat-buffer-included-p (current-buffer))) 177 | (should 178 | (equal nil 179 | hardhat-reasons)) 180 | (kill-buffer (current-buffer)))) 181 | 182 | (ert-deftest hardhat-example-file-14 nil 183 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 184 | (find-file "./examples/perl_modepat.pl") 185 | (should 186 | (hardhat-buffer-included-p (current-buffer))) 187 | (should 188 | (equal (list 'protected 'bof-content "# Changes made here will be lost when autosplit is run again") 189 | hardhat-reasons)) 190 | (kill-buffer (current-buffer)))) 191 | 192 | (ert-deftest hardhat-example-file-15 nil 193 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 194 | (find-file "./examples/text_perlmodepat.txt") 195 | (should-not 196 | (hardhat-buffer-included-p (current-buffer))) 197 | (should 198 | (equal nil 199 | hardhat-reasons)) 200 | (kill-buffer (current-buffer)))) 201 | 202 | (ert-deftest hardhat-example-file-16 nil 203 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file")) 204 | (hardhat-buffer-protected-functions nil)) 205 | (find-file "./examples/protected-autoloads.el") 206 | (should 207 | (hardhat-buffer-included-p (current-buffer))) 208 | (should 209 | (equal (list 'protected 'basename "-autoloads.el") 210 | hardhat-reasons)) 211 | (kill-buffer (current-buffer)))) 212 | 213 | (ert-deftest hardhat-example-file-17 nil 214 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file")) 215 | (hardhat-buffer-protected-functions nil)) 216 | (find-file "./examples/editpat-autoloads.el") 217 | (should-not 218 | (hardhat-buffer-included-p (current-buffer))) 219 | (should 220 | (equal (list 'editable 'bof-content ";; allow editing this file") 221 | hardhat-reasons)) 222 | (kill-buffer (current-buffer)))) 223 | 224 | (ert-deftest hardhat-example-file-18 nil 225 | (find-file "./examples/shell-editpat.sh") 226 | (should-not 227 | (hardhat-buffer-included-p (current-buffer))) 228 | (should 229 | (equal (list 'editable 'bof-content "THIS IS A GENERATED FILE\\") 230 | hardhat-reasons)) 231 | (kill-buffer (current-buffer))) 232 | 233 | (ert-deftest hardhat-example-file-19 nil 234 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 235 | (find-file "./examples/CVS/text_protpath.txt") 236 | (should 237 | (hardhat-buffer-included-p (current-buffer))) 238 | (should 239 | (equal (list 'protected 'fullpath "/CVS/") 240 | hardhat-reasons)) 241 | (kill-buffer (current-buffer)))) 242 | 243 | (ert-deftest hardhat-example-file-20 nil 244 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 245 | (find-file "./examples/CVS/text_protpath_editpat.txt") 246 | (should-not 247 | (hardhat-buffer-included-p (current-buffer))) 248 | (should 249 | (equal (list 'editable 'bof-content ";; allow editing this file") 250 | hardhat-reasons)) 251 | (kill-buffer (current-buffer)))) 252 | 253 | (ert-deftest hardhat-example-file-21 nil 254 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 255 | (find-file "./examples/CVS/elisp_protpath_localnil.el") 256 | (hardhat-local-variables-hook) 257 | (should-not 258 | (hardhat-buffer-included-p (current-buffer))) 259 | (should-not 260 | hardhat-mode) 261 | (should 262 | (equal (list 'editable 'file-local-variable nil) 263 | hardhat-reasons)) 264 | (kill-buffer (current-buffer)))) 265 | 266 | (ert-deftest hardhat-example-file-22 nil 267 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 268 | (find-file "./examples/CVS/elisp_protpath_localt.el") 269 | (hardhat-local-variables-hook) 270 | (should-not 271 | (hardhat-buffer-included-p (current-buffer))) 272 | (should 273 | hardhat-mode) 274 | (should 275 | (equal (list 'protected 'file-local-variable t) 276 | hardhat-reasons)) 277 | (kill-buffer (current-buffer)))) 278 | 279 | (ert-deftest hardhat-example-file-23 nil 280 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 281 | (find-file "./examples/CVS/bash-fc-0") 282 | (should-not 283 | (hardhat-buffer-included-p (current-buffer))) 284 | (should 285 | (equal (list 'editable 'basename "bash-fc-0") 286 | hardhat-reasons)) 287 | (kill-buffer (current-buffer)))) 288 | 289 | (ert-deftest hardhat-example-file-24 nil 290 | "cover hardhat-protected-osx-homebrew" 291 | :expected-result (if (and (eq system-type 'darwin) 292 | (file-writable-p "/usr/local/README.md")) :passed :failed) 293 | (let ((hardhat-bof-content-editable-regexps '("^;+ *allow editing this file"))) 294 | (find-file "/usr/local/README.md") 295 | (should 296 | (hardhat-buffer-included-p (current-buffer))) 297 | (should 298 | (equal (list 'protected 'function 'hardhat-protected-osx-homebrew) 299 | hardhat-reasons)) 300 | (kill-buffer (current-buffer)))) 301 | 302 | 303 | ;;; hardhat-customize-set-regexp (symbol value) -- todo 304 | 305 | 306 | ;;; hardhat-local-hook (&rest args) -- todo 307 | 308 | 309 | ;;; hardhat-global-hook (&rest args) -- todo 310 | 311 | 312 | ;;; hardhat-mode -- todo 313 | 314 | 315 | ;; 316 | ;; Emacs 317 | ;; 318 | ;; Local Variables: 319 | ;; indent-tabs-mode: nil 320 | ;; mangle-whitespace: t 321 | ;; require-final-newline: t 322 | ;; coding: utf-8 323 | ;; byte-compile-warnings: (not cl-functions) 324 | ;; End: 325 | ;; 326 | 327 | ;;; hardhat-test.el ends here 328 | -------------------------------------------------------------------------------- /hardhat.el: -------------------------------------------------------------------------------- 1 | ;;; hardhat.el --- Protect against clobbering user-writable files -*- lexical-binding: t -*- 2 | ;; 3 | ;; Copyright (c) 2012-2015 Roland Walker 4 | ;; 5 | ;; Author: Roland Walker 6 | ;; Homepage: http://github.com/rolandwalker/hardhat 7 | ;; URL: http://raw.githubusercontent.com/rolandwalker/hardhat/master/hardhat.el 8 | ;; Version: 0.4.6 9 | ;; Last-Updated: 14 Apr 2016 10 | ;; EmacsWiki: Hardhat 11 | ;; Package-Requires: ((emacs "24.3") (ignoramus "0.7.0")) 12 | ;; Keywords: convenience 13 | ;; 14 | ;; Simplified BSD License 15 | ;; 16 | ;;; Commentary: 17 | ;; 18 | ;; Quickstart 19 | ;; 20 | ;; (require 'hardhat) 21 | ;; 22 | ;; (global-hardhat-mode 1) 23 | ;; 24 | ;; ;; now you are protected from editing: 25 | ;; ;; 26 | ;; ;; .git/index 27 | ;; ;; ~/.emacs.d/elpa/hardhat-0.1.0/hardhat.el 28 | ;; ;; ~/.emacs~ 29 | ;; ;; 30 | ;; ;; and many others 31 | ;; 32 | ;; Explanation 33 | ;; 34 | ;; A recent unwholesome trend is for package managers to install files 35 | ;; in locations such as ~/.cabal/, ~/.rvm/, or ~/.emacs.d/elpa/. It 36 | ;; is rarely meant for such files to be edited; doing so can cause 37 | ;; data loss in some circumstances. 38 | ;; 39 | ;; In addition, many user-writable files created in the course of 40 | ;; ordinary work should never be altered by a text editor, eg the 41 | ;; database stored in a .git directory. 42 | ;; 43 | ;; Hardhat.el provides an extra layer of protection in your work. If 44 | ;; you visit a file which looks unsafe to edit, Emacs will make the 45 | ;; buffer read-only -- even when the underlying file is writable. 46 | ;; 47 | ;; The read-only protection can be turned off for a buffer by the 48 | ;; usual methods, or by toggling off buffer-local hardhat-mode via 49 | ;; the lighter menu or 50 | ;; 51 | ;; M-x hardhat-mode RET 52 | ;; 53 | ;; If a buffer is not visiting a file, `hardhat-mode' has no effect. 54 | ;; If the visited file is not writable by the user, `hardhat-mode' 55 | ;; has no effect. 56 | ;; 57 | ;; To use hardhat, place the hardhat.el library somewhere 58 | ;; Emacs can find it, and add the following to your ~/.emacs file: 59 | ;; 60 | ;; (require 'hardhat) 61 | ;; (global-hardhat-mode 1) 62 | ;; 63 | ;; To inquire as to why hardhat has set or unset protection in 64 | ;; a buffer, the following interactive command is provided 65 | ;; 66 | ;; `hardhat-status' 67 | ;; 68 | ;; but not bound to any key. 69 | ;; 70 | ;; See Also 71 | ;; 72 | ;; M-x customize-group RET hardhat RET 73 | ;; 74 | ;; Notes 75 | ;; 76 | ;; `hardhat-mode' takes no action until the user attempts an 77 | ;; interactive command in a buffer. This is (out of an abundance 78 | ;; of caution) for compatibility: an Emacs Lisp library may freely 79 | ;; open and write to a file protected by `hardhat-mode', so long as 80 | ;; it is done programatically. 81 | ;; 82 | ;; For any of the options settable in customize, rules making 83 | ;; buffers "editable" override rules making buffers "protected". 84 | ;; 85 | ;; A Boolean file-local variable `hardhat-protect' is provided. 86 | ;; When `hardhat-protect' is set to either t or nil, no other 87 | ;; rules are consulted. 88 | ;; 89 | ;; Regular-expression matches are case-insensitive. A case- 90 | ;; sensitive test can be implemented by adding custom function 91 | ;; to eg `hardhat-buffer-protected-functions'. 92 | ;; 93 | ;; Compatibility and Requirements 94 | ;; 95 | ;; GNU Emacs version 25.1-devel : not tested 96 | ;; GNU Emacs version 24.5 : not tested 97 | ;; GNU Emacs version 24.4 : yes 98 | ;; GNU Emacs version 24.3 : yes 99 | ;; GNU Emacs version 23.3 : yes 100 | ;; GNU Emacs version 22.2 : yes, with some limitations 101 | ;; GNU Emacs version 21.x and lower : unknown 102 | ;; 103 | ;; Uses if present: ignoramus.el 104 | ;; 105 | ;; Prior art 106 | ;; 107 | ;; do-not-edit.el 108 | ;; http://user42.tuxfamily.org/do-not-edit/index.html 109 | ;; Kevin Ryde 110 | ;; 111 | ;; Bugs 112 | ;; 113 | ;; More exceptions are certainly needed in `hardhat-fullpath-editable-regexps' 114 | ;; 115 | ;; Because Emacs can wedge if `file-truename' is called on a 116 | ;; remote file (eg when using TRAMP), some filename tests used in 117 | ;; hardhat are not precisely equivalent between local and remote 118 | ;; files. You can change this behavior by setting 119 | ;; `hardhat-use-unsafe-remote-truename' via customize. A better 120 | ;; solution is to set `find-file-visit-truename' globally. 121 | ;; 122 | ;; TODO 123 | ;; 124 | ;;; License 125 | ;; 126 | ;; Simplified BSD License: 127 | ;; 128 | ;; Redistribution and use in source and binary forms, with or 129 | ;; without modification, are permitted provided that the following 130 | ;; conditions are met: 131 | ;; 132 | ;; 1. Redistributions of source code must retain the above 133 | ;; copyright notice, this list of conditions and the following 134 | ;; disclaimer. 135 | ;; 136 | ;; 2. Redistributions in binary form must reproduce the above 137 | ;; copyright notice, this list of conditions and the following 138 | ;; disclaimer in the documentation and/or other materials 139 | ;; provided with the distribution. 140 | ;; 141 | ;; This software is provided by Roland Walker "AS IS" and any express 142 | ;; or implied warranties, including, but not limited to, the implied 143 | ;; warranties of merchantability and fitness for a particular 144 | ;; purpose are disclaimed. In no event shall Roland Walker or 145 | ;; contributors be liable for any direct, indirect, incidental, 146 | ;; special, exemplary, or consequential damages (including, but not 147 | ;; limited to, procurement of substitute goods or services; loss of 148 | ;; use, data, or profits; or business interruption) however caused 149 | ;; and on any theory of liability, whether in contract, strict 150 | ;; liability, or tort (including negligence or otherwise) arising in 151 | ;; any way out of the use of this software, even if advised of the 152 | ;; possibility of such damage. 153 | ;; 154 | ;; The views and conclusions contained in the software and 155 | ;; documentation are those of the authors and should not be 156 | ;; interpreted as representing official policies, either expressed 157 | ;; or implied, of Roland Walker. 158 | ;; 159 | ;;; Code: 160 | ;; 161 | 162 | ;;; requirements 163 | 164 | ;; for callf, setf, callf2, assert, remove-if-not 165 | (require 'cl-lib) 166 | 167 | (require 'ignoramus nil t) 168 | 169 | ;;; declarations 170 | 171 | (eval-when-compile 172 | (defvar ert--running-tests)) 173 | 174 | ;;; set-function for customize 175 | 176 | (defvar hardhat-computed-regexps (make-hash-table :test 'eq) 177 | "Per-mode cache for regexps computed from defcustom settings.") 178 | 179 | ;;;###autoload 180 | (defun hardhat-customize-set-regexp (symbol value) 181 | "Set function which clears the computed regexp cache. 182 | 183 | SYMBOL and VALUE are passed to `custom-set-default'." 184 | (custom-set-default symbol value) 185 | (setq hardhat-computed-regexps (make-hash-table :test 'eq))) 186 | 187 | ;;; customizable variables 188 | 189 | ;;;###autoload 190 | (defgroup hardhat nil 191 | "Protect against clobbering user-writable files." 192 | :version "0.4.6" 193 | :link '(emacs-commentary-link :tag "Commentary" "hardhat") 194 | :link '(url-link :tag "GitHub" "http://github.com/rolandwalker/hardhat") 195 | :link '(url-link :tag "EmacsWiki" "http://emacswiki.org/emacs/Hardhat") 196 | :prefix "hardhat-" 197 | :group 'convenience) 198 | 199 | (defcustom hardhat-mode-lighter " hhat" 200 | "This string appears in the mode-line when `hardhat-mode' is active. 201 | 202 | Set to nil or the empty string to disable the mode-line 203 | lighter for `hardhat-mode'." 204 | :type 'string 205 | :group 'hardhat) 206 | (put 'hardhat-mode-lighter 'risky-local-variable t) 207 | 208 | (defcustom hardhat-less-feedback nil 209 | "Give less echo area feedback." 210 | :type 'boolean 211 | :group 'hardhat) 212 | 213 | (defcustom hardhat-bof-content-bound 250 214 | "How far from the start to search for regexps in content. 215 | 216 | See `hardhat-bof-content-protected-regexps' and `hardhat-bof-content-editable-regexps'." 217 | :type 'integer 218 | :group 'hardhat) 219 | 220 | (defcustom hardhat-eof-content-bound 250 221 | "How far from the end to search for regexps in content. 222 | 223 | See `hardhat-eof-content-protected-regexps' and `hardhat-eof-content-editable-regexps'." 224 | :type 'integer 225 | :group 'hardhat) 226 | 227 | (defcustom hardhat-use-unsafe-remote-truename nil 228 | "Unconditionally use `file-truename' on remote files. 229 | 230 | This makes certain checks more accurate, but can wedge Emacs if 231 | your connection to a remote host is lost." 232 | :type 'boolean 233 | :group 'hardhat) 234 | 235 | ;;;###autoload 236 | (defgroup hardhat-protect nil 237 | "Rules for activating `hardhat-mode' protection in a buffer." 238 | :group 'hardhat) 239 | 240 | (defcustom hardhat-bof-content-protected-regexps '( 241 | (emacs-lisp-mode . "\\`;;;;[^\n]*--- automatically extracted\\>") 242 | (perl-mode . "^# Changes made here will be lost when autosplit is run again\\>") 243 | (cperl-mode . "^# Changes made here will be lost when autosplit is run again\\>") 244 | "\\" 245 | "\\" 246 | "\\" 247 | "\\" 248 | "\\" 249 | "\\" 250 | "\\`;+ *Emacs Bookmark Format Version [0-9]" 251 | "^;+ *-+ smex-history -+" 252 | "^;+ *EIEIO PERSISTENT OBJECT\\>" 253 | "^;+ *Tramp connection history\\>" 254 | ) 255 | "Protect buffer from editing if these patterns match near beginning-of-file. 256 | 257 | Patterns can be specified on a per-mode basis using a cons cell 258 | in the form \(mode . regexp\). The customization interface can 259 | arrange this for you automatically. 260 | 261 | All patterns are case-insensitive." 262 | :set 'hardhat-customize-set-regexp 263 | :type '(repeat (choice (regexp :tag "Regular expression") 264 | (cons :tag "Mode-specific regular expression" 265 | (symbol :tag "Mode") 266 | (regexp :tag "Mode-specific regular expression")))) 267 | :group 'hardhat-protect) 268 | 269 | (defcustom hardhat-eof-content-protected-regexps '( 270 | ) 271 | "Protect buffer from editing if these patterns match near end-of-file. 272 | 273 | Patterns can be specified on a per-mode basis using a cons cell 274 | in the form \(mode . regexp\). The customization interface can 275 | arrange this for you automatically. 276 | 277 | All patterns are case-insensitive." 278 | :set 'hardhat-customize-set-regexp 279 | :type '(repeat (choice (regexp :tag "Regular expression") 280 | (cons :tag "Mode-specific regular expression" 281 | (symbol :tag "Mode") 282 | (regexp :tag "Mode-specific regular expression")))) 283 | :group 'hardhat-protect) 284 | 285 | (defcustom hardhat-basename-protected-regexps '( 286 | "~\\'" 287 | "\\.lock\\'" 288 | "\\.ix\\'" 289 | "\\`test\\.out\\'" 290 | "-autoloads\\.el\\'" 291 | "\\`Desktop\\.ini\\'" 292 | "\\`META\\.yml\\'" 293 | "\\`MYMETA\\.yml\\'" 294 | "\\`TAGS\\'" 295 | "\\`Thumbs\\.db\\'" 296 | "\\`\\.dropbox\\'" 297 | "\\`\\.dropbox\\.cache\\'" 298 | "\\`\\.emacs\\.desktop\\'" 299 | "\\`\\.emacs\\.desktop\\.lock\\'" 300 | "\\.orig\\'" 301 | "\\.rej\\'" 302 | ) 303 | "Protect buffer from editing if these patterns match filename (sans directory). 304 | 305 | Patterns can be specified on a per-mode basis using a cons cell 306 | in the form \(mode . regexp\). The customization interface can 307 | arrange this for you automatically. 308 | 309 | All patterns are case-insensitive." 310 | :set 'hardhat-customize-set-regexp 311 | :type '(repeat (choice (regexp :tag "Regular expression") 312 | (cons :tag "Mode-specific regular expression" 313 | (symbol :tag "Mode") 314 | (regexp :tag "Mode-specific regular expression")))) 315 | :group 'hardhat-protect) 316 | 317 | (defcustom hardhat-fullpath-protected-regexps '( 318 | "~/\\.emacs\\.d/elpa/" 319 | "~/\\.cpan/" 320 | "~/\\.cabal/" 321 | "~/perl5/perlbrew/" 322 | "~/\\.npm/" 323 | "~/\\.virtualenv/" 324 | "~/\\.virthualenv/" 325 | "~/\\.rvm/" 326 | "/[._]build/" 327 | "/\\.bzr/" 328 | "/\\.coverage/" 329 | "/\\.git/" 330 | "/\\.hg/" 331 | "/\\.rspec/" 332 | "/\\.sass-cache/" 333 | "/\\.svn/" 334 | "/_MTN/" 335 | "/_darcs/" 336 | "/CVS/" 337 | "/pm_to_blib/" 338 | "/RCS/" 339 | "/SCCS/" 340 | "/blib/" 341 | "/test_output/" 342 | "~/\\.emacs\\.d/\\.cask/" 343 | "~/\\.cask/" 344 | ) 345 | "Protect buffer from editing if these patterns match into full path to file. 346 | 347 | A leading \"~/\" expression will be expanded with the user's home 348 | directory. The path this pattern is tested against will be fully 349 | expanded. 350 | 351 | Patterns can be specified on a per-mode basis using a cons cell 352 | in the form \(mode . regexp\). The customization interface can 353 | arrange this for you automatically. 354 | 355 | All patterns are case-insensitive." 356 | :set 'hardhat-customize-set-regexp 357 | :type '(repeat (choice (regexp :tag "Regular expression") 358 | (cons :tag "Mode-specific regular expression" 359 | (symbol :tag "Mode") 360 | (regexp :tag "Mode-specific regular expression")))) 361 | :group 'hardhat-protect) 362 | 363 | (defcustom hardhat-buffer-protected-functions '( 364 | hardhat-protected-by-ignoramus 365 | hardhat-protected-osx-homebrew 366 | (perl-mode . hardhat-protected-by-perl-semantic-eof) 367 | (cperl-mode . hardhat-protected-by-perl-semantic-eof) 368 | ) 369 | "Protect buffer from editing if any listed function evaluates non-nil. 370 | 371 | Each function should take two arguments in the form \(buffer 372 | &optional file\). 373 | 374 | Functions can be specified on a per-mode basis using a cons cell 375 | in the form \(mode . function\). The customization interface can 376 | arrange this for you automatically. 377 | 378 | Set this value to nil to disable." 379 | :type '(repeat (choice (function :tag "Function") 380 | (cons :tag "Mode-specific function" 381 | (symbol :tag "Mode") 382 | (regexp :tag "Mode-specific function")))) 383 | :group 'hardhat-protect) 384 | 385 | ;;;###autoload 386 | (defgroup hardhat-editable nil 387 | "Rules for de-activating `hardhat-mode', making text editable." 388 | :group 'hardhat) 389 | 390 | (defcustom hardhat-bof-content-editable-regexps '( 391 | (sh-mode . "\\ " hardhat-lighter-menu-mouse-button)) menu-map) 543 | map) "Keymap for the global `hardhat-mode' lighter.") 544 | 545 | ;;; macros 546 | 547 | (defmacro hardhat-called-interactively-p (&optional kind) 548 | "A backward-compatible version of `called-interactively-p'. 549 | 550 | Optional KIND is as documented at `called-interactively-p' 551 | in GNU Emacs 24.1 or higher." 552 | (cond 553 | ((not (fboundp 'called-interactively-p)) 554 | '(interactive-p)) 555 | ((condition-case nil 556 | (progn (called-interactively-p 'any) t) 557 | (error nil)) 558 | `(called-interactively-p ,kind)) 559 | (t 560 | '(called-interactively-p)))) 561 | 562 | ;;; compatibility functions 563 | 564 | (unless (fboundp 'string-match-p) 565 | ;; added in 23.x 566 | (defun string-match-p (regexp string &optional start) 567 | "Same as `string-match' except this function does not change the match data." 568 | (let ((inhibit-changing-match-data t)) 569 | (string-match regexp string start)))) 570 | 571 | (unless (fboundp 'with-demoted-errors) 572 | ;; added in 23.x 573 | (defmacro with-demoted-errors (&rest body) 574 | "Run BODY and demote any errors to simple messages." 575 | (declare (debug t) (indent 0)) 576 | (let ((err (make-symbol "err"))) 577 | `(condition-case ,err 578 | (progn ,@body) 579 | (error (message "Error: %S" ,err) nil))))) 580 | 581 | ;;; utility functions 582 | 583 | (defun hardhat--propertize-lighter () 584 | "Add properties to the `hardhat-mode' lighter." 585 | (when (and (stringp hardhat-mode-lighter) 586 | (> (length hardhat-mode-lighter) 0)) 587 | (cl-callf propertize hardhat-mode-lighter 588 | hardhat-lighter-keymap-property hardhat-lighter-map 589 | 'help-echo (format "Hardhat: mouse-%s menu" hardhat-lighter-menu-mouse-button)))) 590 | 591 | (defun hardhat-compute-regexps () 592 | "Compute regexps from customizable values." 593 | (unless (gethash major-mode hardhat-computed-regexps) 594 | (puthash major-mode (make-hash-table :test 'eq) hardhat-computed-regexps) 595 | (save-match-data 596 | ;; read variables 597 | (dolist (directive hardhat-directives) 598 | (puthash directive (make-hash-table :test 'eq) 599 | (gethash major-mode hardhat-computed-regexps)) 600 | (dolist (criterion (remq 'function hardhat-criteria)) 601 | (let ((cust-sym (intern (format "hardhat-%s-%s-regexps" criterion directive))) 602 | (computed nil)) 603 | (dolist (elt (symbol-value cust-sym)) 604 | (cond 605 | ((null elt) 606 | t) 607 | ((stringp elt) 608 | (push elt computed)) 609 | ((and (consp elt) 610 | (stringp (cdr elt)) 611 | (symbolp (car elt))) 612 | (when (eq major-mode (car elt)) 613 | (push (cdr elt) computed))) 614 | (t 615 | (error "Bad element %s in %s" elt cust-sym))) 616 | ;; tilde expansion 617 | (when (and (eq criterion 'fullpath) 618 | (string-match "\\`\\(~[^~/]*/\\)" (car computed))) 619 | (setf (car computed) 620 | (replace-match 621 | (regexp-quote (expand-file-name (match-string 1 (car computed)))) 622 | nil 623 | 'literal 624 | (car computed) 625 | 1)))) 626 | ;; sanity check 627 | (when computed 628 | (cl-callf2 cl-remove-if-not 'stringp computed) 629 | (cl-callf2 cl-remove-if-not #'(lambda (str-val) 630 | (> (length str-val) 0)) computed)) 631 | ;; construct and store regexp 632 | (when computed 633 | (setq computed (format "\\(%s\\)" (mapconcat 'identity computed "\\|"))) 634 | (puthash criterion computed (gethash directive (gethash major-mode hardhat-computed-regexps)))))))))) 635 | 636 | (defun hardhat-safe-file-truename (filename) 637 | "Return the truename of FILENAME if it is safe to do so. 638 | 639 | `file-truename' can wedge infinitely for remote files in the case 640 | that the connection to the remote host is lost. 641 | 642 | This is a safer wrapper which employs `file-truename' for local 643 | files only. For remote files, the following is used 644 | 645 | (file-remote-p FILENAME 'localname) 646 | 647 | which, though *not* equivalent to `file-truename', is better than 648 | a wedge. 649 | 650 | This behavior can be overridden by setting customizable variable 651 | `hardhat-use-unsafe-remote-truename' to a non-nil value." 652 | (or (and (not hardhat-use-unsafe-remote-truename) 653 | (file-remote-p filename 'localname)) 654 | (file-truename filename))) 655 | 656 | ;;; functions which may de/activate protection 657 | 658 | (defun hardhat-dispatch-generic-check (buf directive criterion &optional file basename) 659 | "Return non-nil if hardhat check is true for BUF. 660 | 661 | DIRECTIVE may be a symbol listed in `hardhat-directives'. 662 | 663 | CRITERION may be a symbol listed in `hardhat-criteria'. 664 | 665 | Optional FILE and BASENAME override the file and basename 666 | associated with BUF for the purpose of optimization." 667 | (when (and (or (not noninteractive) ert--running-tests) 668 | (bufferp buf) 669 | (or file basename (buffer-file-name buf))) 670 | (cl-assert (memq directive hardhat-directives) nil "Bad DIRECTIVE") 671 | (cl-assert (memq criterion hardhat-criteria) nil "Bad CRITERION") 672 | (with-current-buffer buf 673 | (cond 674 | ((eq criterion 'function) 675 | (catch 'hit 676 | (dolist (cell (symbol-value (intern (format "hardhat-buffer-%s-functions" directive)))) 677 | (let ((test (cond 678 | ((symbolp cell) 679 | cell) 680 | ((and (consp cell) 681 | (eq major-mode (car cell))) 682 | (cdr cell))))) 683 | (when (and (fboundp test) 684 | (with-demoted-errors (funcall test buf file))) 685 | (throw 'hit test)))))) 686 | (t 687 | (hardhat-compute-regexps) 688 | (let ((case-fold-search t) 689 | (regexp (ignore-errors 690 | (gethash criterion 691 | (gethash directive 692 | (gethash major-mode hardhat-computed-regexps)))))) 693 | (when (and (stringp regexp) 694 | (> (length regexp) 0)) 695 | (save-excursion 696 | (save-restriction 697 | (save-match-data 698 | (unless hardhat--respect-narrowing 699 | (widen)) 700 | (cond 701 | ((eq criterion 'basename) 702 | (cl-callf or basename (file-name-nondirectory (hardhat-safe-file-truename (buffer-file-name buf)))) 703 | (when (string-match regexp basename) 704 | (match-string 1 basename))) 705 | ((eq criterion 'fullpath) 706 | (cl-callf or file (hardhat-safe-file-truename (buffer-file-name buf))) 707 | (when (string-match regexp file) 708 | (match-string 1 file))) 709 | ((eq criterion 'bof-content) 710 | (goto-char (point-min)) 711 | (when (re-search-forward regexp hardhat-bof-content-bound t) 712 | (match-string-no-properties 1))) 713 | ((eq criterion 'eof-content) 714 | (goto-char (point-max)) 715 | (when (re-search-backward regexp (- (point-max) hardhat-eof-content-bound) t) 716 | (match-string-no-properties 1))) 717 | (t 718 | (error "Bad DIRECTIVE"))))))))))))) 719 | 720 | (defun hardhat-protected-by-ignoramus (buf &optional file) 721 | "Return non-nil if `ignoramus-boring-p' is true for file associated with BUF. 722 | 723 | Optional FILE overrides the file associated with BUF for the 724 | purpose of optimization. 725 | 726 | If ignoramus.el is not present, fails silently. 727 | 728 | This function may be used as a member of `hardhat-buffer-protected-functions'." 729 | (when (and (fboundp 'ignoramus-boring-p) 730 | (bufferp buf)) 731 | (cl-callf or file (hardhat-safe-file-truename (expand-file-name (buffer-file-name buf)))) 732 | (when (ignoramus-boring-p file) 733 | buf))) 734 | 735 | (defun hardhat-dispatch-perl-check (buf directive &optional file) 736 | "Dispatch check for perl semantic eof functions on BUF. 737 | 738 | DIRECTIVE may be a symbol listed in `hardhat-directives'. 739 | 740 | Optional FILE overrides the file associated with BUF for the 741 | purpose of optimization. 742 | 743 | See `hardhat-editable-by-perl-semantic-eof' and 744 | `hardhat-protected-by-perl-semantic-eof'" 745 | (with-current-buffer buf 746 | (when (and (or (not noninteractive) ert--running-tests) 747 | (bufferp buf) 748 | (or file (buffer-file-name buf))) 749 | (save-excursion 750 | (save-restriction 751 | (save-match-data 752 | (widen) 753 | (goto-char (point-min)) 754 | (when (let ((case-fold-search nil)) 755 | (search-forward-regexp "^__\\(?:DATA\\|END\\)__$" nil t)) 756 | (narrow-to-region (point-min) (line-beginning-position)) 757 | (let ((hardhat--respect-narrowing t)) 758 | (hardhat-dispatch-generic-check buf directive 'eof-content file))))))))) 759 | 760 | (defun hardhat-protected-by-perl-semantic-eof (buf &optional file) 761 | "Return non-nil if protection regexps match near end of code in BUF. 762 | 763 | `hardhat-eof-content-protected-regexps' are tested above a 764 | __DATA__ or __END__ marker, which marks the end of code 765 | in a Perl file. 766 | 767 | Optional FILE overrides the file associated with BUF for the 768 | purpose of optimization. 769 | 770 | This function may be used as a member of `hardhat-buffer-protected-functions'." 771 | (hardhat-dispatch-perl-check buf 'protected file)) 772 | 773 | (defun hardhat-editable-by-perl-semantic-eof (buf &optional file) 774 | "Return non-nil if editable regexps match near end of code in BUF. 775 | 776 | `hardhat-eof-content-editable-regexps' are tested above a 777 | __DATA__ or __END__ marker, which marks the end of code 778 | in a Perl file. 779 | 780 | Optional FILE overrides the file associated with BUF for the 781 | purpose of optimization. 782 | 783 | This function may be used as a member of `hardhat-buffer-editable-functions'." 784 | (hardhat-dispatch-perl-check buf 'editable file)) 785 | 786 | (defun hardhat-protected-osx-homebrew (buf &optional file) 787 | "Return non-nil if BUF is visiting a Homebrew file on OS X. 788 | 789 | The Homebrew project \(http://mxcl.github.com/homebrew/\) 790 | encourages the installation of user-writable files under 791 | /usr/local/. 792 | 793 | Optional FILE overrides the file associated with BUF for the 794 | purpose of optimization." 795 | (when (eq system-type 'darwin) 796 | (cl-callf or file (hardhat-safe-file-truename (expand-file-name (buffer-file-name buf)))) 797 | (when (and (string-match-p "\\`/usr/local/" file) 798 | (file-writable-p file)) 799 | buf))) 800 | 801 | (defun hardhat-buffer-included-p (buf) 802 | "Return BUF if `global-hardhat-mode' should enable `hardhat-mode' in BUF." 803 | (when (and (or (not noninteractive) ert--running-tests) 804 | (bufferp buf) 805 | (buffer-file-name buf) 806 | (not buffer-read-only) 807 | (not buffer-file-read-only)) 808 | (let* ((file (hardhat-safe-file-truename (expand-file-name (buffer-file-name buf)))) 809 | (basename (file-name-nondirectory file)) 810 | (answer nil)) 811 | (when (fboundp 'ignoramus-compute-common-regexps) 812 | (ignoramus-compute-common-regexps)) 813 | (unless (eq 'file-local-variable (cadr hardhat-reasons)) 814 | (setq hardhat-reasons (catch 'hardhat 815 | (dolist (directive hardhat-directives) 816 | (dolist (criterion hardhat-criteria) 817 | (when (setq answer (hardhat-dispatch-generic-check buf directive criterion file basename)) 818 | (throw 'hardhat (list directive criterion answer))))))) 819 | (when (eq 'protected (car hardhat-reasons)) 820 | buf))))) 821 | 822 | ;;; minor-mode definition 823 | 824 | ;;;###autoload 825 | (define-minor-mode hardhat-mode 826 | "Turn on `hardhat-mode'. 827 | 828 | When called interactively with no prefix argument this command 829 | toggles the mode. With a prefix argument, it enables the mode 830 | if the argument is positive and otherwise disables the mode. 831 | 832 | When called from Lisp, this command enables the mode if the 833 | argument is omitted or nil, and toggles the mode if the argument 834 | is 'toggle." 835 | :group 'hardhat 836 | (cond 837 | (hardhat-mode 838 | (cond 839 | ((and (or (not noninteractive) ert--running-tests) 840 | (buffer-file-name (current-buffer)) 841 | (not buffer-read-only) 842 | (not buffer-file-read-only)) 843 | (when (and (stringp hardhat-mode-lighter) 844 | (not (local-variable-p 'hardhat-mode-lighter))) 845 | (make-local-variable 'hardhat-mode-lighter) 846 | (cl-callf concat hardhat-mode-lighter "[on]") 847 | (hardhat--propertize-lighter)) 848 | (add-hook 'pre-command-hook 'hardhat-local-hook nil t) 849 | (when (hardhat-called-interactively-p 'interactive) 850 | (setq hardhat-reasons (list 'protected 'user-interactive 'hardhat-mode-toggled)) 851 | (when (not hardhat-less-feedback) 852 | (message "hardhat-mode enabled")))) 853 | (t 854 | (when (and (hardhat-called-interactively-p 'interactive) 855 | (not hardhat-less-feedback)) 856 | (message "hardhat-mode cannot be enabled in this buffer")) 857 | (setq hardhat-mode nil)))) 858 | (t 859 | (when (stringp (default-value 'hardhat-mode-lighter)) 860 | (kill-local-variable 'hardhat-mode-lighter)) 861 | (cond 862 | ((hardhat-called-interactively-p 'interactive) 863 | (setq hardhat-reasons (list 'editable 'user-interactive 'hardhat-mode-toggled))) 864 | ((eq (car hardhat-reasons) 'protected) 865 | (setq hardhat-reasons nil))) 866 | (remove-hook 'pre-command-hook 'hardhat-local-hook t) 867 | (unless buffer-file-read-only 868 | (setq buffer-read-only nil)) 869 | (when (and (hardhat-called-interactively-p 'interactive) 870 | (not hardhat-less-feedback)) 871 | (message "hardhat-mode disabled"))))) 872 | 873 | ;;; global minor-mode definition 874 | 875 | (defun hardhat-maybe-turn-on (&optional arg) 876 | "Activate `hardhat-mode' in a buffer if appropriate. 877 | 878 | The buffer must be file-associated to be considered. The pathname 879 | of the associated file is tested according to 880 | 881 | `hardhat-basename-protected-regexps' 882 | `hardhat-fullpath-protected-regexps' 883 | 884 | The content of the buffer is tested according to 885 | 886 | `hardhat-bof-content-protected-regexps' 887 | `hardhat-eof-content-protected-regexps' 888 | 889 | In addition, the buffer is tested according to the functions in 890 | 891 | `hardhat-buffer-protected-functions' 892 | `hardhat-buffer-editable-functions' 893 | 894 | If called with a negative ARG, deactivate `hardhat-mode' in the buffer." 895 | (cl-callf or arg 1) 896 | (when (or (< arg 0) 897 | (hardhat-buffer-included-p (current-buffer))) 898 | (hardhat-mode arg))) 899 | 900 | ;; The global mode function is written by hand, avoiding the macro 901 | ;; `define-globalized-minor-mode', so as to confine checking to 902 | ;; specific hooks. Otherwise checks would fire much more often. 903 | ;;;###autoload 904 | (defun global-hardhat-mode (&optional arg) 905 | "Toggle Hardhat mode in all buffers. 906 | With prefix ARG, enable Global-Hardhat mode if ARG is positive; 907 | otherwise, disable it. If called from Lisp, enable the mode if 908 | ARG is omitted or nil." 909 | (interactive "P") 910 | (cond 911 | ((hardhat-called-interactively-p 'interactive) 912 | (cl-callf or arg (if global-hardhat-mode -1 1))) 913 | (t 914 | (cl-callf or arg 1))) 915 | (cl-callf prefix-numeric-value arg) 916 | (cond 917 | ((< arg 0) 918 | (remove-hook 'find-file-hook 'hardhat-global-hook) 919 | (remove-hook 'after-change-major-mode-hook 'hardhat-global-hook) 920 | (remove-hook 'hack-local-variables-hook 'hardhat-local-variables-hook) 921 | (setq global-hardhat-mode nil) 922 | (dolist (buf (cl-remove-if-not #'(lambda (buf) 923 | (ignore-errors 924 | (buffer-local-value 'hardhat-mode buf))) 925 | (buffer-list))) 926 | (with-current-buffer buf 927 | (hardhat-mode -1))) 928 | (when (and (hardhat-called-interactively-p 'interactive) 929 | (not hardhat-less-feedback)) 930 | (message "Global-Hardhat mode disabled"))) 931 | (t 932 | (hardhat--propertize-lighter) 933 | (unless (assoc 'global-hardhat-mode minor-mode-alist) 934 | (push '(global-hardhat-mode hardhat-mode-lighter) minor-mode-alist)) 935 | (dolist (buf (buffer-list)) 936 | (with-current-buffer buf 937 | (hardhat-maybe-turn-on))) 938 | (add-hook 'find-file-hook 'hardhat-global-hook) 939 | (add-hook 'after-change-major-mode-hook 'hardhat-global-hook) 940 | (add-hook 'hack-local-variables-hook 'hardhat-local-variables-hook) 941 | (setq global-hardhat-mode t) 942 | (when (and (hardhat-called-interactively-p 'interactive) 943 | (not hardhat-less-feedback)) 944 | (message "Global-Hardhat mode enabled"))))) 945 | 946 | (defun global-hardhat-mode--setter (sym val) 947 | (cl-assert (eq sym 'global-hardhat-mode) nil 948 | "This function should only be called on `global-hardhat-mode'.") 949 | (global-hardhat-mode (if val 1 -1)) 950 | (set-default sym val)) 951 | 952 | (defcustom global-hardhat-mode nil 953 | "Non-nil if Global-Hardhat mode is enabled. 954 | See the command `global-hardhat-mode' for a description of this minor mode. 955 | Setting this variable directly does not take effect; 956 | either customize it (see the info node `Easy Customization') 957 | or call the function `global-hardhat-mode'." 958 | :group 'hardhat 959 | :type 'boolean 960 | :set #'global-hardhat-mode--setter) 961 | 962 | ;;; hooks 963 | 964 | (defun hardhat-local-variables-hook (&rest _ignored) 965 | "Hook to check a buffer for `hardhat-mode' protection based on file-locals. 966 | 967 | The file-local variable `hardhat-protect' is tested. 968 | 969 | Any arguments are ignored." 970 | (when (and (or (not noninteractive) ert--running-tests) 971 | (buffer-file-name (current-buffer)) 972 | (not buffer-read-only) 973 | (not buffer-file-read-only)) 974 | (cond 975 | ((not (local-variable-p 'hardhat-protect)) 976 | t) 977 | ((eq hardhat-protect t) 978 | (setq hardhat-reasons (list 'protected 'file-local-variable t)) 979 | (hardhat-mode 1)) 980 | ((eq hardhat-protect nil) 981 | (setq hardhat-reasons (list 'editable 'file-local-variable nil)) 982 | (hardhat-mode -1))))) 983 | 984 | (defun hardhat-local-hook (&rest _ignored) 985 | "Hook to check a buffer for `hardhat-mode' protection. 986 | 987 | Any arguments are ignored." 988 | (remove-hook 'pre-command-hook 'hardhat-local-hook t) 989 | (when (and hardhat-mode 990 | (or (not noninteractive) ert--running-tests) 991 | (buffer-file-name (current-buffer)) 992 | (not buffer-read-only) 993 | (not buffer-file-read-only)) 994 | (setq buffer-read-only t) 995 | (unless hardhat-less-feedback 996 | (message "hardhat: protecting %s from edits because: %s test matched \"%s\"" 997 | (current-buffer) 998 | (nth 1 hardhat-reasons) 999 | (nth 2 hardhat-reasons))))) 1000 | 1001 | (defun hardhat-global-hook (&rest _ignored) 1002 | "Hook to check all buffers for `hardhat-mode' protection. 1003 | 1004 | Any arguments are ignored." 1005 | (when global-hardhat-mode 1006 | (with-demoted-errors 1007 | (hardhat-maybe-turn-on)))) 1008 | 1009 | ;;; interactive commands 1010 | 1011 | ;;;###autoload 1012 | (defun hardhat-status () 1013 | "Echo the `hardhat-mode' status of the current buffer." 1014 | (interactive) 1015 | (cond 1016 | (hardhat-reasons 1017 | (message "Hardhat marked this buffer %s, because: %s test matched \"%s\"" 1018 | (car hardhat-reasons) 1019 | (nth 1 hardhat-reasons) 1020 | (nth 2 hardhat-reasons))) 1021 | ((and (not hardhat-reasons) 1022 | hardhat-mode) 1023 | (message "Bug: hardhat-mode is on but results are not available")) 1024 | ((not hardhat-reasons) 1025 | (message "Hardhat-mode did not mark this buffer")) 1026 | ((not global-hardhat-mode) 1027 | (message "Hardhat-mode is off globally")) 1028 | (t 1029 | (message "No status information available.")))) 1030 | 1031 | (provide 'hardhat) 1032 | 1033 | ;; 1034 | ;; Emacs 1035 | ;; 1036 | ;; Local Variables: 1037 | ;; indent-tabs-mode: nil 1038 | ;; mangle-whitespace: t 1039 | ;; require-final-newline: t 1040 | ;; coding: utf-8 1041 | ;; byte-compile-warnings: (not cl-functions redefine) 1042 | ;; End: 1043 | ;; 1044 | ;; LocalWords: Hardhat ARGS alist devel Ryde callf defcustom hhat 1045 | ;; LocalWords: autosplit EIEIO smex virtualenv perlbrew virthualenv 1046 | ;; LocalWords: setf cpan rspec darcs elpa 1047 | ;; 1048 | 1049 | ;;; hardhat.el ends here 1050 | --------------------------------------------------------------------------------