Compare commits

...

339 Commits
cqP ... master

Author SHA1 Message Date
Tim Pope 2bab337396 Merge pull request #259 from rm-hull/bugfix/handle-nREPL-stacktrace
Handle new/old nREPL stacktraces - fixes #258
2016-01-29 16:03:38 -05:00
Richard Hull 0814dd0d2d Handle new/old nREPL stacktraces - fixes #258
At some point there was an upstream change to the message format that
cider-nrepl returned. This resulted in in a crash when trying to eval
an expression that threw an exception, resulting in the exception
being obscured by a Vim error, and no stacktrace being produced.
This patch inspects the returned payload and optionally extracts
any embedded stacktrace before processing.
2016-01-29 20:45:57 +00:00
Tim Pope b550ac6680 Merge pull request #254 from smy20011/master
Use CRLF on windows when parsing test result
2015-12-29 00:46:03 -05:00
Siyuan Ma fd18e8481d Use "\r\\=\n" indicate line break. 2015-12-28 22:17:03 -06:00
Tim Pope fd94f70fff Merge pull request #251 from SevereOverfl0w/patch-1
Replace leiningen.vim with salve.vim
2015-12-07 21:03:48 -05:00
Dominic Monroe 2d5177abef Replace leiningen.vim with salve.vim 2015-12-07 20:52:52 +00:00
Tim Pope 1c75b56ceb Sort bencode keys
Closes https://github.com/tpope/vim-fireplace/issues/248
2015-11-30 19:31:27 -05:00
Daniel Silva f57537135a Add FireplaceEvalPost autocommand
Closes #232.
2015-11-13 18:29:41 -05:00
Tim Pope 8579a41a18 Merge pull request #239 from siphiuel/master
Change :Piggieback behavior for empty/port parameters
2015-10-02 12:12:42 -04:00
Vitaliy Vlasov 3474bd5d72 Change :Piggieback behavior for empty/port parameters
- Explicitly specify Rhino REPL when :Piggieback has no parameters

- Use Weasel REPL when port parameter is provided to :Piggieback

- Improve leading space handling for :Piggieback params

- Fall back to cljs.repl.browser if Weasel in not in classpath

- Use has_key() when checking for Weasel repl availability
2015-10-02 11:07:28 +03:00
Tim Pope 3ffdb062c6 Allow for empty lists in ns declaration 2015-09-30 12:52:10 -04:00
Tim Pope b1725f68a1 Determine aliases by statically parsing ns declaration 2015-09-30 12:22:01 -04:00
Tim Pope 7d500028e6 Rearrange 2015-09-28 18:02:10 -04:00
Juho Teperi df563ed15f Fix alias edge case detection in cfile 2015-09-28 15:00:06 -04:00
Tim Pope 04a7f542f5 Improve error on piggieback failure
References #167.
2015-09-22 14:29:07 -04:00
Tim Pope 3d9b9a59cd Merge pull request #236 from janko-m/runtests-error
Fix a runtime error in :RunTests
2015-08-24 14:23:19 -04:00
Janko Marohnić 9a770d3716 Fix a runtime error in :RunTests 2015-08-24 11:54:05 +02:00
Tim Pope b3b54b8715 Merge pull request #231 from nberger/use-test-vars-on-single-var
Run (single) test under cursor with fixtures applied
2015-07-31 14:39:19 -04:00
Nicolas Berger b50e74f342 Run test under cursor with fixtures applied
Use `test-vars` instead of `test-var` so the test runs with the fixtures
applied. That's the expected behavior when running a test. It's also
what's being done when multiple tests are matched.
2015-07-31 14:53:12 -03:00
Tim Pope 9f7b1844cf Merge pull request #229 from kul/master
Remove superfluous padding from expression
2015-07-18 12:51:18 -04:00
kul 74d392339c Remove superfluous padding from expression 2015-07-18 12:23:31 +05:30
Tim Pope a1571cd258 fireplace.vim 1.1
* Support cider completion, including context aware completion.
* Updates for latest cider-nrepl and piggieback.
* Use :.RunTests or 1cpr to run test under cursor.
* Add CTRL-R CTRL-F and CTRL-R CTRL-P command line maps.
* Add support for boot's fake class path.
* Fix handling of CTRL-C interrupt while evaling.
* Numerous minor bug fixes.
2015-06-30 18:34:36 -04:00
Tim Pope f456f04b65 Work around bug on ancient Vim
Closes #226.
2015-06-29 17:46:45 -04:00
Tim Pope 09c80c6794 Allow 1cpr to run test under cursor 2015-06-26 09:36:14 -04:00
Tim Pope 459904381b Use :.RunTests to run test under cursor
Closes #223.
2015-06-25 15:34:45 -04:00
Tim Pope 69bf9ef519 Make :0RunTests equivalent to RunAllTests 2015-06-25 15:04:12 -04:00
Tim Pope 1f478e401a Tweak <cfile> 2015-06-25 10:17:58 -04:00
Tim Pope cb3c270c99 Add cljc extension support to connection process 2015-06-23 15:56:50 -04:00
Tim Pope 7b2ae78bd7 Add <C-R> command line maps 2015-06-21 15:12:39 -04:00
Tim Pope b0a540c68d Add .cljc extension 2015-06-21 15:08:30 -04:00
Tim Pope 09eedd05af Use jar command if available to query zip files 2015-06-21 15:08:29 -04:00
Tim Pope 89aee9c00c Merge pull request #214 from Deraen/completion-context
Completion context
2015-05-17 11:01:43 -04:00
Juho Teperi c22e61c69b Add support for context aware completion
If complete operation is given context property containing the
current toplevel form Compliment library can give better completion
results in some contexts:

- Local vars for let and defn
- Resources in classpath for io/resource calls
- Vars in specific ns for :require :refer
- Better Java class name completion for :import

The context string should contain symbol __prefix__ in place of the word
being completed. To achieve this location of cursor inside the toplevel
form is calculated so that the placeholder symbol can be placed in the
proper place.
2015-05-17 17:54:06 +03:00
Roger Gilliar 13a21bff0f Fix count of test errors and failures
Closes #208.
2015-05-17 10:06:21 -04:00
Tim Pope 1646a01b0b Merge pull request #211 from Deraen/all-candidate-types
Add all candidate types to short_types map
2015-05-16 16:17:59 -04:00
Juho Teperi aede23c46a Add all candidate types to short_types map 2015-05-16 23:01:23 +03:00
Tim Pope 819438bdf4 Merge pull request #210 from Deraen/cider-nrepl-0.9.0
Cider nrepl 0.9.0 completion support
2015-05-15 16:19:55 -04:00
Juho Teperi 9ccaea1f2b Request extra-metadata for completion candidates
In cider-nrepl 0.9.0 there is new extra-metadata option for complete op
[1]. It can be used to enrich the candiate results with additional
properties like arglists and docstring.

This commit adds extra-metadata option to complete call and changes the
candidate function to set fields in omnicomplete result so that arglists
are shown on omnicomplete menu and docstring is shown in preview window.

[1]: https://github.com/clojure-emacs/cider-nrepl/pull/195/files
2015-05-15 22:54:08 +03:00
Juho Teperi 44e766d5a5 Add support for Cider-nrepl 0.9.0 complete op
Response from complete operation now returns list of maps containing
e.g. namespace and type of the completion candidate.
This change adds a new type check to check if complete returned list of
maps and converts those maps to format required by omnicomplete.
In addition to candidate name its type is now shown. The type is
shortned to one character.
2015-05-15 22:31:54 +03:00
Tim Pope 49153a39fc Merge pull request #201 from kul/master
Remove `:repl-env` for latest piggieback compatibility.
2015-04-13 16:27:49 -04:00
kul 0aabcdd798 Remove `:repl-env` for latest piggieback compatibility. 2015-03-31 20:52:10 +05:30
Joshua Davey 5866d0017a Add support for boot 2.0 and up
Boot's built-in repl task adds a fake.class.path System property which
refers back to the original user files (as opposed to the temporary
files it uses to actually do builds). We should prefer that to anything
else when the property is set.

Fixes #194.
2015-02-15 13:45:21 -05:00
Robert Pitts 7cebf6847e Document `cqq` 2015-02-10 15:27:43 -05:00
Tim Pope 71e44af208 Fix c1mm 2015-02-10 11:11:53 -05:00
Tim Pope b999b09cd9 Fix project directory path for autoconnection
Closes #189.
2014-12-20 01:27:23 -05:00
Tim Pope 506cf288bd Skip regexp when selecting form for cpp
Closes #188.
2014-12-11 11:31:23 -05:00
Tim Pope 0ecd9ec587 Fix duplicate namespaces in completion 2014-11-30 00:53:32 -05:00
Tim Pope 874505e9f2 Support new return value of completions operator 2014-11-30 00:46:33 -05:00
Tim Pope 04ce1b64af Support new return value of classpath operator 2014-11-30 00:36:33 -05:00
Tim Pope db2e70ee3f Cider info op no longer embeds in value attribute
Closes #186.
2014-11-19 00:49:58 -05:00
Tim Pope 8f7a07cffd Allow forcing default ns 2014-10-23 15:52:50 -04:00
Tim Pope 97758acc16 Fix sending interrupt commands after SIGINT
Via @benmoss.  Closes #182.
2014-10-21 15:29:31 -04:00
Tim Pope eeccb69a2f Fix typo 2014-10-21 15:14:38 -04:00
Tim Pope c0e574387d Fix completion in aliased namespaces 2014-10-10 02:40:10 -04:00
Tim Pope fccb149148 Recognize nested classes in K
Closes #176.
2014-09-05 13:10:21 -04:00
Tim Pope c1416c89ba Don't choke on missing API version
Closes #175.
2014-09-02 12:26:13 -04:00
Tim Pope b256399f3f Merge pull request #169 from oahner/fix-portfile-issue
Register port file after connecting to port
2014-07-31 10:34:32 -04:00
Jonathan Henry 142fab4e0f Register port file after connecting to port 2014-07-31 00:57:15 -04:00
Tim Pope 06f6bc5de6 Evaluate single expression when running tests
This eliminates an extra "nil" value in the response.
2014-07-12 23:17:30 -04:00
Tim Pope d6b3e1c67c Silence all callback errors
If this is to be made asynchronous, there's not really a good way to
display the exception.
2014-07-10 22:58:35 -04:00
Tim Pope ebb2933f4c Pass additional .message arguments to callback 2014-07-10 22:43:03 -04:00
Tim Pope 3e978e4cd4 Add better name for fireplace#evalparse() 2014-07-04 17:14:10 -04:00
Tim Pope a39092ebe3 Add script id 2014-07-04 17:00:21 -04:00
Tim Pope 835fdedf5f fireplace.vim 1.0 2014-07-04 16:50:18 -04:00
Tim Pope e107b2ae17 Drop reference to old name 2014-07-04 16:32:52 -04:00
Tim Pope 1dc5129c0e Tweak description 2014-07-04 16:24:46 -04:00
Tim Pope 712205e66a Normalize headers 2014-07-04 16:06:43 -04:00
Tim Pope ffc41e86f3 Remove obsolete Maven reference 2014-07-04 15:38:00 -04:00
Tim Pope 37e3a474c5 Clarify plugin/fireplace/zip.vim 2014-07-04 15:04:44 -04:00
Tim Pope 1f36136346 Zip hack unnecessary on Vim 7.4 2014-07-03 14:49:18 -04:00
Tim Pope ea15c81773 Remove extracted compiler plugin 2014-07-03 14:45:11 -04:00
Tim Pope 25e18b5f82 Support gf on relative (load) paths
This doesn't do a file existence check because that's tricky with jar
files in the mix.  Instead, it's limited to strings, so a gf on a random
symbol doesn't send us flying.
2014-07-03 12:30:32 -04:00
Tim Pope a14328c1dc Allow disabling all maps 2014-07-03 12:28:23 -04:00
Tim Pope eae17cfb42 Drop 'includeexpr' entirely 2014-07-03 10:22:55 -04:00
Tim Pope 845b362a17 Find absolute path in 'includeexpr'
The gf map is still necessary because Vim doesn't accept zipfile paths
as valid.
2014-07-03 10:02:34 -04:00
Tim Pope a1eef3dda1 Rearrange 2014-07-03 09:52:28 -04:00
Tim Pope 0e42998a27 Provide :RunAllTests
Don't waste :RunTests! on this cleverness.
2014-07-02 19:20:11 -04:00
Tim Pope 9c78e32f4b Add plugin maps for go to file 2014-07-02 18:44:20 -04:00
Tim Pope fb6975bfdf Extract autocmd repetition to functions 2014-07-02 18:38:49 -04:00
Tim Pope 8defd6b17e Fix grammar: setup -> set_up 2014-07-02 18:33:23 -04:00
Tim Pope 26e467c2e7 Fix list of available protocols
Closes #165.
2014-07-01 09:19:32 -04:00
Tim Pope 6dbf627022 Make connect commands buffer local 2014-06-29 19:03:49 -04:00
Tim Pope 5ff2eeae1c Default to nrepl protocol 2014-06-29 18:54:07 -04:00
Tim Pope 94ff1464a4 Fix manual connection 2014-06-29 18:53:41 -04:00
Tim Pope f2b6a2101f Ignore errors on autorequire if namespace created
Closes #161.
2014-06-27 13:30:12 -04:00
Tim Pope b10259bcca Fix naming inconsistency 2014-06-27 11:17:13 -04:00
Tim Pope bfdd052fc7 Section header style change 2014-06-27 09:46:21 -04:00
Tim Pope c657faaf4e Remove transitional support 2014-06-27 09:45:00 -04:00
Tim Pope e4b975eaec Don't clobber K map
Closes #163.
2014-06-25 14:52:01 -04:00
Tim Pope 2cbaacf0d0 Fix bdecode of negative number
Closes #162.
2014-06-17 22:35:45 -04:00
Tim Pope 83a317c10b Merge pull request #160 from jgdavey/docs
Update documentation: keyword -> symbol
2014-06-11 15:09:02 -04:00
Joshua Davey e6c4b5547a Update documentation: keyword -> symbol 2014-06-11 10:41:10 -05:00
Tim Pope 049005dec7 Merge pull request #152 from jgdavey/brepl
Browser piggieback connection convenience
2014-06-10 17:56:43 -04:00
Bohr Shaw 88648b2578 Feed &cedit as a key properly - fix #62 2014-05-20 19:52:24 -04:00
Tim Pope 67078e0c34 Clarify projectionist requirement
Closes #153.
2014-05-19 19:26:13 -04:00
Joshua Davey 99d93ceba1 Browser piggieback connection convenience
When you provide a port number, you are implicitly saying you're
listening for a browser connection.
2014-05-14 08:57:31 -05:00
Tim Pope 29af4adc46 Kill :Apropos
This is broken for anything namespaced.  REPL-y's find-name is better,
but nonstandard.
2014-05-05 15:24:26 -04:00
Tim Pope ac88f17bb4 Move window logic into test capture 2014-05-05 01:31:36 -04:00
Tim Pope af14811869 Capture test run errors 2014-05-05 01:23:30 -04:00
Tim Pope 0b17709b56 Don't blow up on unrecognized session 2014-05-05 01:16:00 -04:00
Tim Pope fa7a19140b Allow sending custom id on eval 2014-05-05 00:59:35 -04:00
Tim Pope 6cea463c97 Set title on test quickfix window 2014-05-04 22:42:58 -04:00
Tim Pope fff348ccd0 Respect 'autowrite' in :Require and :RunTests 2014-05-04 18:09:56 -04:00
Tim Pope 020a10d06c Use info op for :Doc
This should enable ClojureScript support.
2014-05-01 22:26:53 -04:00
Tim Pope afb036203e Drop Leiningen and alternate support 2014-04-29 21:28:28 -04:00
Tim Pope 58896e23fa Fix cpp documentation
Closes #148.
2014-04-29 20:47:00 -04:00
Tim Pope 57c18b778a Promote leiningen.vim over classpath.vim
Classpath.vim as a clearinghouse for classpath detection is officially
deprecated, though the plugin may take on other responsibilities such as
stacktrace parsing.
2014-04-29 17:34:09 -04:00
Tim Pope 0bc928f0fc Automatic require :reload on :RunTests
Really, I just want an atomic way to perform these two operations.
:Require|RunTests seems like it would work, but it obliviously runs the
tests even if the require fails, plus copes poorly with the one-off
runner.
2014-04-28 23:06:21 -04:00
Tim Pope 062256b9fd Fix link 2014-04-28 15:58:35 -04:00
Tim Pope a2278afbdd Document soft dependency on cider-nrepl 2014-04-24 23:31:04 -04:00
Tim Pope 9eb5099ba1 Clarify ClojureScript support
Closes #147.
2014-04-24 02:13:00 -04:00
Tim Pope 12386dc0c2 Fix newlines in c!
Closes #146.
2014-04-23 23:16:02 -04:00
Tim Pope 05cbc742a1 Use classpath op if available
References #131.
2014-04-23 14:52:08 -04:00
Tim Pope e484ad6996 Use info op to drive jump to definition 2014-04-20 18:55:37 -04:00
Tim Pope e974dd4766 Prepare for extraction of leiningen support 2014-04-20 18:53:01 -04:00
Tim Pope 2d1f3088b2 Fix :RunTests with no argument 2014-04-14 01:55:16 -04:00
Tim Pope f25003deef Decouple quickfix massaging from lein support 2014-04-14 00:22:43 -04:00
Tim Pope c0a4901181 Fix support for Python 3
Closes #144.
2014-04-13 17:07:47 -04:00
Tim Pope 7b19c1b2f6 Require if_pyth on Windows
References #97, #139.
2014-04-12 22:18:26 -04:00
Tim Pope 672d3b5c82 Use stacktrace nrepl op if available 2014-04-12 22:03:14 -04:00
Tim Pope 0936b3cb4f Use correct session to retrieve stacktrace 2014-04-12 21:57:01 -04:00
Tim Pope 05206aa2e9 Drop obsolete warning 2014-04-12 21:55:28 -04:00
Tim Pope 5f1cee19c0 Never throw exception in fireplace#op_available 2014-04-12 21:49:45 -04:00
Tim Pope c6e0d55143 Use nrepl complete op if available
Closes #65.
2014-04-12 21:20:15 -04:00
Tim Pope 89acd66d6d Drop qualification of macroexpand-1
Who would shadow this?
2014-04-12 21:18:18 -04:00
Tim Pope feb8ebc976 Happy path for lookup macros 2014-04-12 21:18:18 -04:00
Tim Pope f5ded81baf Drop unnecessary clojure.core
We're in a clean user ns so the qualification is unnecessary here.
2014-04-12 21:18:18 -04:00
Tim Pope 238b526cf2 Use user ns to avoid qualification 2014-04-12 21:18:18 -04:00
Tim Pope 9e826faff4 Allow omitting ns from fireplace#message 2014-04-12 20:31:18 -04:00
Tim Pope 79c2a718da Allow checking for nREPL op 2014-04-12 20:31:18 -04:00
Tim Pope c48adc045b Fix jump location for :RunTests error 2014-04-12 20:28:34 -04:00
Tim Pope bc8f3af299 Cleaner classpath retrieval 2014-04-12 18:15:22 -04:00
Tim Pope 2dec3b49b2 Expose fireplace#register_port_file
References #121.
2014-04-10 23:25:59 -04:00
Tim Pope ea1012e1be Don't use session for :Source/:Doc 2014-04-09 13:23:19 -04:00
Tim Pope 916fc04ecb Don't depend on classpath.vim
Other plugins should be able to set up the path as well without
classpath.vim serving as a clearinghouse.
2014-04-09 13:20:13 -04:00
Tim Pope ead617d9c3 Centralize use of classpath.vim 2014-04-09 12:45:54 -04:00
Tim Pope f43fa99703 Fix check for haslocaldir() 2014-04-05 19:27:41 -04:00
Tim Pope 6130d01b33 Give up on autostart with "headless" handler 2014-04-04 02:15:25 -04:00
Tim Pope b0f9fad9ec Autostart lein repl with dispatch.vim
Great idea?  Or greatest idea?
2014-04-04 01:57:43 -04:00
Tim Pope 4425618825 Add run-tests to cpr
Clobbering the quickfix is probably a deal breaker but hey let's try it
anyways.

References #59.
2014-04-04 00:58:52 -04:00
Tim Pope 092ab0f70e Provide :RunTests
:RunTests! currently calls (run-all-tests), but if we find a more useful
semantic for ! that might change.

Closes #59.
2014-04-04 00:58:21 -04:00
Tim Pope 73f9a3adf4 Not a noob anymore 2014-04-03 23:53:12 -04:00
Tim Pope 6c13396262 Remove dead code 2014-04-03 21:16:42 -04:00
Tim Pope 9a689480ef Better rooting with findfile()
I think this is more portable.
2014-04-03 21:09:00 -04:00
Tim Pope ab5eee34d8 Support .nrepl-port outside of Leiningen 2014-04-03 21:03:26 -04:00
Tim Pope 1bfb5aadcf Update name of preferred port file in README 2014-04-03 19:46:29 -04:00
Tim Pope ab6d9db216 Tentatively drop support for session eval without REPL
I'm not 100% committed to this, but lets see if anyone even misses it
(including me).  My main use case for the one-off runner is jump to
source.
2014-04-03 19:37:47 -04:00
Tim Pope 095ee57d12 Revert "Steal Windows shell escaping from dispatch.vim"
This reverts commit 15450eff27.
2014-04-03 18:57:18 -04:00
Tim Pope da3f5857b5 Respect jump list on ]<C-D> within same file
Closes #70.
2014-04-03 18:23:24 -04:00
Tim Pope d65eaa5068 Fix c!! with selection=inclusive
References #110.
2014-04-03 16:23:13 -04:00
Tim Pope 90b909b9f4 Use innermost form with cpp et al
Closes #119.
2014-03-29 20:52:31 -04:00
Tim Pope 15450eff27 Steal Windows shell escaping from dispatch.vim 2014-03-21 01:38:51 -04:00
Tim Pope b139d72da4 Fix check for classpath function 2014-03-21 01:38:45 -04:00
Tim Pope 6fefd47170 Merge pull request #140 from cursork/remove-ansi-colours
Remove ansi colours escape codes in output
2014-03-20 17:58:14 -04:00
Neil Kirsopp 77b06741ef Remove ANSI escapes from stderr as well 2014-03-20 17:11:16 +00:00
Neil Kirsopp 72794b36d9 Remove ANSI from standard out 2014-03-20 16:50:40 +00:00
Tim Pope 31eaa4455e Merge pull request #136 from sjl/preview-arglists
Add arglists to the omnicomplete preview window
2014-02-17 12:05:01 -05:00
Steve Losh 3a843cb1b1 Add arglists to the omnicomplete preview window
When you use omnicomplete the arglists of functions are shown in the
popup menu and the docstrings in the preview window.  This patch adds
the arglists into the preview window too.  This is handy because once
you select a completion you'll still be able to see the arglists as you
write the rest of the form.
2014-02-14 19:38:58 -05:00
Tim Pope 544769274a Merge pull request #135 from benmoss/patch-1
Note CLJS classpath requirement
2014-02-08 13:22:27 -05:00
Ben Moss 9d76d14ca4 Note CLJS classpath requirement
Addresses #132
2014-02-08 11:09:25 -05:00
Tim Pope 97d78f6829 Allow quotes in :Piggieback argument
Closes #134.
2014-02-05 20:29:09 -05:00
Tim Pope d3e6bd34ae Fix check for b:fireplace_ns
Closes #133.
2014-02-05 10:19:01 -05:00
Tim Pope 5a86ec2c81 Fix lein stacktrace parsing without live REPL 2014-01-30 23:30:53 -05:00
Tim Pope eb27299bd9 Parse stacktraces from :make with lein 2014-01-30 23:13:57 -05:00
Tim Pope 7bc3ee4c1a Merge pull request #130 from andrewwong1221/python3-octal-fix
Fixing Python3 Octal Constant Compatibility Issue
2014-01-29 12:03:17 -08:00
Andrew D. Wong e5f636af2f Convert octal constants for Python compatibility 2014-01-29 08:48:05 -05:00
Tim Pope 0095241a6f :Piggieback 2014-01-19 17:59:40 -05:00
Tim Pope 226c5a0fd1 Special case :Require in cljs 2014-01-18 23:26:27 -05:00
Tim Pope 766c8d6bc9 Don't require successful ns load to send nREPL message 2014-01-18 23:25:44 -05:00
Tim Pope 385d8288db Fix null namespace issue 2014-01-18 23:15:53 -05:00
Tim Pope 81ca22bfe2 Fix cpp with piggieback 2014-01-17 22:16:18 -05:00
Tim Pope 0d7b97df7c Initial piggieback support 2014-01-17 20:28:10 -05:00
Tim Pope 0520e4fa32 Extract disconnection cleanup for general use 2014-01-17 17:52:02 -05:00
Tim Pope a568535bcd Support buffer path without classpath.vim 2014-01-17 05:44:42 -05:00
Tim Pope 64f0ae7bbe Extract spawning eval logic 2014-01-17 05:03:09 -05:00
Tim Pope ee141c0256 Do people test ClojureScript? 2014-01-17 04:35:30 -05:00
Tim Pope 6e7f22766a Disconnect when port file disappears 2014-01-17 04:30:46 -05:00
Tim Pope 91e3b35403 Kill debug 2014-01-17 00:27:45 -05:00
Tim Pope 25f17ac25d Fix logic for preserving ns 2014-01-16 01:22:21 -05:00
Tim Pope e6c1f9eac1 Allow ignoring responses at transport layer
Future versions may make this async.
2014-01-16 01:02:10 -05:00
Neil Kirsopp fef85624d3 Anchor to end of ns string 2014-01-15 23:40:36 -05:00
Neil Kirsopp b92a9730f0 Very basic Midje alternate 2014-01-15 23:40:18 -05:00
Tim Pope ef422f66e2 Remove require from client interface 2014-01-15 23:38:04 -05:00
Tim Pope 15f98b06f7 Leverage 'suffixesadd' 2014-01-15 21:37:03 -05:00
Tim Pope 76a99139d1 Remove s:client 2014-01-15 21:37:03 -05:00
Tim Pope 2a6d23f2fc Fix 2014-01-15 19:26:00 -05:00
Torben Rasmussen c5bfcc93f4 Use string formatting supported by older pythons 2014-01-15 13:44:31 -05:00
Tim Pope c4f677ee64 Fix fireplace#source 2014-01-14 16:28:21 -05:00
Tim Pope 4d93831925 Move includes_file out of repl client 2014-01-13 16:37:44 -05:00
Tim Pope 446b0b04b5 Extract contribution guidelines 2014-01-12 16:35:54 -05:00
Tim Pope 7c0c524259 Restore fireplace#eval for compatibility
Use fireplace#session_eval if you want to evaluate something from the
user, and fireplace#evalparse if you want to query for information.
2014-01-12 14:58:28 -05:00
Tim Pope b56e40a2b6 Provide fireplace#path() to access class path 2014-01-12 14:00:13 -05:00
Tim Pope 98cd5e1515 Don't show stacktrace from failed java exec 2014-01-12 13:34:52 -05:00
Tim Pope af245caf76 Propagate require error to eval 2014-01-12 01:06:11 -05:00
Tim Pope 0cfa1eed58 nREPL session cloning 2014-01-12 01:06:02 -05:00
Tim Pope 09a0ed93cf Encapsulate disconnection detection 2014-01-12 01:06:01 -05:00
Tim Pope 9c48439da7 Leverage evalparse 2014-01-12 01:06:01 -05:00
Tim Pope a0fde95d2e Remove unused function 2014-01-12 01:06:01 -05:00
Tim Pope 6a239c93af Indent 2014-01-12 00:52:40 -05:00
Tim Pope 62486afca7 Fix erroneous use of session when none requested 2014-01-12 00:52:40 -05:00
Tim Pope c2a90eb47f One weird trick to force namespace creation 2014-01-11 23:43:08 -05:00
Tim Pope 355580da7e Accidental commit 2014-01-11 21:55:55 -05:00
Tim Pope c99bda551e Use python for zipfile contents when possible 2014-01-11 21:11:09 -05:00
Tim Pope a9c3318817 Provide interface for ignoring a response 2014-01-11 19:29:07 -05:00
Tim Pope 0299eac671 Adjust comment stripping heuristic for cq
Closes #89.
2014-01-11 19:10:45 -05:00
Tim Pope 1c55f88e7f Handle interrupt of eval
Closes #72.
2014-01-11 17:51:44 -05:00
Tim Pope f605cd7824 Do all classpath searching locally
In addition to being cleaner, this means we no longer need to worry
about evaling on a "local" server.
2014-01-11 17:48:04 -05:00
Tim Pope cf094f970f Retrieve ns for arbitrary buffer 2014-01-11 17:48:04 -05:00
Tim Pope 56d667b7d5 Allow retrieving client for arbitrary buffer
Currently, only the one-off client is fully decoupled.
2014-01-11 17:48:04 -05:00
Tim Pope bbab5786df Add missing import 2014-01-11 17:48:04 -05:00
Tim Pope e90aef2ac7 Separate nREPL transport and session concerns
The transport is still doing too much, but it's a good start.
2014-01-10 19:25:35 -05:00
Tim Pope fc0ab71587 Generalize call and add message abstraction 2014-01-10 13:30:32 -05:00
Tim Pope 40bad28354 Allow non-string arguments to python dispatch 2014-01-09 22:21:20 -05:00
Tim Pope 28a6c2c262 Fix cpp on closing bracket
Closes #122.
2014-01-09 14:32:16 -05:00
Tim Pope 52758fd4ea Callback nREPL API
Pass a callback to call to have it invoked for each response message.
This might one day become asynchronous in certain circumstances, but
don't count it.
2014-01-09 01:00:45 -05:00
Tim Pope 382869c6c7 Convenience function for nrepl call
This is mainly for my own debugging, but might evolve in to a real API.
I'm not sure if it's the right place to do a require.
2014-01-09 00:52:25 -05:00
Tim Pope 02f28c5dbb Clean up our sessions 2014-01-08 20:59:08 -05:00
Tim Pope 18d60a3fa5 Allow calling findresource with custom path 2014-01-08 20:05:46 -05:00
Tim Pope 0fdde20654 Better errors on unexpected bencode data
Also fix indent.
2014-01-08 19:59:36 -05:00
Tim Pope 1f3f36505e Unify :Eval and cpp
Now both operations select the exact outermost form use load-file for
proper file/line metadata.
2014-01-08 01:36:39 -05:00
Tim Pope bf4ca57db1 Extract python command generation 2014-01-08 00:50:46 -05:00
Tim Pope 760f50f46e Argument switcharoo 2014-01-07 23:53:20 -05:00
Tim Pope 01e16d236b Extract payload preparation 2014-01-07 23:28:39 -05:00
Tim Pope 02ba3de54e Enable easier testing of Python exec 2014-01-07 23:26:26 -05:00
Tim Pope 15be24fc82 Abort python processes on Vim exit
You'd think a scripting language could handle portably checking if a pid
is still running but no.
2014-01-07 23:07:31 -05:00
Tim Pope 280b8d09b5 Fix warning misfire about broken sessions 2014-01-07 22:15:49 -05:00
Tim Pope c7258fce7c Send and filter by id 2014-01-07 20:03:06 -05:00
Tim Pope 023c8573ab Default to sending session id 2014-01-07 20:01:33 -05:00
Tim Pope 77df83250f Restore accidentally deleted polling 2014-01-07 19:26:23 -05:00
Tim Pope 2073263c07 Generalize interface between Vim and Python 2014-01-07 16:58:47 -05:00
Tim Pope 1b2e58db97 Allow debugging connection failures 2014-01-07 14:07:08 -05:00
Tim Pope 9664516d5f So many missing aborts 2014-01-06 22:58:43 -05:00
Tim Pope 4ce1f8fbfa Python all the way 2014-01-06 22:41:03 -05:00
Tim Pope fa4e0ed143 Fix debugging statement 2014-01-06 22:35:42 -05:00
Tim Pope bb84d556bc Fix :Connect with argument
References #120.
2014-01-06 12:49:12 -05:00
Tim Pope 7277fc4e6d Fix :Connect with no arguments
Closes #120.
2014-01-06 11:38:50 -05:00
Tim Pope 9aa2071b17 Allow overriding buffer namespace 2014-01-01 17:15:35 -05:00
Tim Pope 973014a626 Encapsulate user ns 2014-01-01 13:35:33 -05:00
Tim Pope 90692edc35 Different gross hack for extracting backtrace
Now instead of wrapping the code up in a try/catch, we just use a series
of evals to grab *e and then restore *1/*2/*3.
2013-12-31 20:04:33 -05:00
Tim Pope fb5c946822 Slightly more elaborate hack to detect final nREPL response 2013-12-31 19:35:01 -05:00
Tim Pope 95652fc8c0 Accidental mutation 2013-12-31 19:34:52 -05:00
Tim Pope cd3bf333bf Use nrepl load-file for :[range]Eval
Closes #83.
2013-12-30 14:20:07 -05:00
Tim Pope d3f7f2cf26 Change cpp from innermost to outermost
Closes #116.
2013-12-26 11:21:20 -05:00
Tim Pope f1b8096b3f Merge pull request #108 from actionshrimp/last-err
Include compilation errors in s:history for :Last
2013-10-23 21:25:53 -07:00
Dave Aitken b57c21c29b Include compilation errors in s:history for :Last
If the repl doesn't return a value due to an error during compilation
(EOF due to missing bracket, unrecognised symbol), the response has no
value and as a result is not added to the history. However it's useful
to add it so it can be inspected with :Last to aid with fixing the issue.
2013-10-17 20:06:54 +01:00
Tim Pope 92644485d6 Merge pull request #101 from bnwasteland/lein232-portfile
As of Leiningen 2.3.2 there is yet another portfile convention
2013-09-14 14:48:39 -07:00
Jace Bennett 740ca20ff1 As of Leiningen 2.3.2 there is yet another portfile convention 2013-08-20 23:49:40 -04:00
Tim Pope 52d906b3a4 Merge pull request #98 from jgdavey/master
Search for repl-port file in common places
2013-08-16 10:47:14 -07:00
Joshua Davey 4db39ee484 Search for repl-port file in common places
As of Leiningen 2.3, different profiles activate different target
sub-directories. In the case of the repl, that means the repl-port file
is now located at target/repl/repl-port.
2013-08-14 14:19:16 -05:00
Aaron Miller 0127e5fc54 Fully macroexpand using macroexpand-all 2013-08-06 01:43:19 -04:00
Joshua Davey 235a4ec3e8 Make alternates function public 2013-08-06 01:43:19 -04:00
Tim Pope 8f925c9342 Merge pull request #71 from rasmusto/fugitive-integration
handle "fugitive:.*" file in s:repl.includes_file
2013-08-01 21:50:34 -07:00
Chris Ford 4490d2a882 Macroexpand motions
Bind cm{motion} to full macro expansion of the form described by
the motion (using clojure.core/macroexpand), and bind c1m{motion}
to partial macro expansion of the form described by the motion
(using clojure.core/macroexpand-1).

cmm and c1mm will apply the expansion to the form under the cursor.
2013-07-23 18:18:31 -04:00
Tim Pope b96ccf7441 Merge pull request #85 from benmoss/master
Fix typo in docs
2013-06-30 19:26:14 -07:00
Ben Moss 204a8de243 Fix typo 2013-06-30 18:59:59 -04:00
Torben Rasmussen 34e0d0c964 handle "fugitive:.*" files in s:repl.includes_file
When sending code to the repl from a fugitive :Gd
or :Ge, remove the "fugitive://" prefix, and
"/.git/<rev number>/" path from the buffer name.

This allows for evaluation of code from previous
revisions of a file when inside of a fugitive :Gdiff
or :Gedit window.
2013-04-27 12:23:41 -07:00
Tim Pope 4f6b8e5237 Don't auto-open location list
Closes #48.
2013-04-19 16:47:53 -04:00
Tim Pope 7984a4c260 Fix cryptic error on :Connect 2013-04-19 16:47:37 -04:00
Tim Pope 2efe294efb Fix for newer Pythons 2013-04-19 11:41:51 -04:00
Tim Pope 55255578bb Cease deleting stale port files
The Leiningen 2 prereleases liked to leave stale port files behind, but
this is fixed in the final release.
2013-04-18 11:12:49 -04:00
Tim Pope 77444275fd Support Python 2.4 2013-04-17 13:35:47 -04:00
Tim Pope 93df7ca18f Fix FAQ heading level 2013-04-17 10:56:40 -04:00
Tim Pope f58065f0d1 Add fireplace help topic 2013-04-16 16:59:19 -04:00
Jacek Lach 5aa33b2cca Handle single keyword metadata on namespace name
I.e. (ns ^:integration my-namespace)
2013-04-10 22:37:31 -04:00
Tim Pope 21d5c81eab Clean up require errors on gf and ]d 2013-04-10 22:34:28 -04:00
Sam Umbach 7b334ef5a3 Fix minor typo 2013-04-10 18:55:18 -03:00
Tim Pope 83ce4440ae Take away cpR
@cemerick says I should take away all the reloading and just support
load-file, but I'm starting with the most egregious offender.
2013-04-04 13:49:11 -04:00
Tim Pope 1b92e0a7dd Fix global setting of 'nomodifiable'
It doesn't make sense that we have to do this, as 'nomodifiable' is
documented as being buffer local.

Closes #58.
2013-04-01 13:09:19 -04:00
Tim Pope db27257f7f Rename foreplay.vim to fireplace.vim 2013-03-13 19:56:13 -04:00
Tim Pope fa6e35bc19 Remove old vendored classpath.vim 2013-03-13 19:49:03 -04:00
Tim Pope 1a8eab85d9 Clarify dependencies 2013-03-13 19:43:27 -04:00
Tim Pope a7f460ad1b Assume Leiningen 2 in documentation 2013-03-13 19:43:23 -04:00
Tim Pope d40c8d9c41 Point at vim-clojure-static in help file 2013-03-12 16:31:48 -04:00
Tim Pope c1c3f9e917 Typo fix 2013-03-12 16:06:05 -04:00
Tim Pope 699dff447f Better representation of require errors
Should help with #56.
2013-03-06 17:15:57 -05:00
Tim Pope 5b57f37802 Allow non-interactive :Connect
Closes #46.
2013-02-14 00:12:45 -05:00
Tim Pope 8d253a9fdf Support speclj in :A
Closes #45.
2013-02-13 18:31:13 -05:00
Tim Pope 873623df59 Fix spacing in error 2013-02-13 12:58:50 -05:00
Dave Ray 7d47c7ec4c Qualify clojure.core symbols
I was having problems with the raw use of list in the :Doc command as
well as require in :Require. Fully qualifying them fixes the issue.
2013-02-12 19:53:22 -08:00
Tim Pope 8c0eae19ab Gather escaping functions 2013-02-10 13:30:26 -05:00
Tim Pope 9749177034 Don't assume src/ in Leiningen projects
Fun fact: it's impossible to reliably predict whether a given
project.clj is a Leiningen project file or not.

Closes #51.
2013-02-10 11:48:48 -05:00
Tim Pope eff7bcec61 Rename functions again 2013-02-08 12:14:58 -05:00
Tim Pope a1068949b1 Support booleans in foreplay#evalparse 2013-02-08 10:26:14 -05:00
Tim Pope a6012b5032 Rename foreplay#eval to foreplay#eval_pr_str
Goal is to rename foreplay#evalparse to foreplay#eval.
2013-02-08 00:35:15 -05:00
Tim Pope b94a694254 Rename foreplay#evalprint to foreplay#eval_prn 2013-02-08 00:34:13 -05:00
Jeremy Holland 47ea532d8e Fix typo 2013-02-05 11:12:51 -05:00
Tim Pope 105b01d7d0 Provide :Last
Closes #7.
2013-01-29 19:15:21 -05:00
Tim Pope d2bc102487 Alternate between test and implementation
Closes #33.
2013-01-25 12:27:03 -05:00
Tim Pope f653f18e64 Fix gf when file hasn't been required yet
Closes #44.
2013-01-25 11:22:10 -05:00
Jacek Lach 511a123421 Decode paths for aliased namespaces. 2013-01-25 15:09:04 +00:00
Tim Pope 53201c89de Fix recognition of REPL disconnection 2013-01-24 16:38:00 -05:00
Tim Pope 7ff2191a30 Automatically open location list on exception
Closes #39.
2013-01-23 22:23:42 -05:00
Tim Pope cd54b73e88 Fix Ruby nREPL connection on Windows
I do not understand why tripling quotes escapes them.

Closes #41.
2013-01-19 23:11:04 -05:00
Tim Pope c0bdf9b971 Fix decoding URLs 2013-01-19 23:06:57 -05:00
Tim Pope a80ff87f94 Better handling of resource paths on Windows
References #40.
2013-01-19 23:01:53 -05:00
Tim Pope 274c4da054 Apply fnameescape() to source location
References #40.
2013-01-19 16:32:57 -05:00
Paul deGrandis da70e71023 Fixed a typo bug; gd in new tab 2013-01-19 12:33:44 -08:00
Tim Pope f4e9f1c10a Use namespaces in critical path 2013-01-16 01:01:09 -05:00
Tim Pope aed21575b8 Fix stack trace parsing with "Unknown Source"
Closes #37.
2013-01-15 21:35:40 -05:00
Tim Pope 123bea5850 Fix stack trace parsing with one-off runner 2013-01-15 21:34:41 -05:00
Tim Pope fd8d623b7b Catch one line stack traces
References #38.
2013-01-15 20:45:44 -05:00
Tim Pope 6f93e99ede Strip all carriage returns out of output
Closes #38.
2013-01-15 20:17:59 -05:00
Tim Pope fbd8a0844a OCD 2013-01-15 20:04:46 -05:00
Tim Pope 1db6dbed3f Cache executable('zipinfo') for speed on Windows
Closes #36.
2013-01-15 19:17:55 -05:00
Tim Pope 879443c846 Fewer explosions when gf goes wrong 2013-01-13 10:28:25 -05:00
Tim Pope 286a1f6c47 Allow interrupting nREPL connection
Closes #30.
2013-01-10 23:09:54 -05:00
Tim Pope 7a36f4e8b8 Remove if_ruby adapter
The list of things worse than if_ruby is pretty short, and does not
include if_pyth.
2013-01-09 00:41:46 -05:00
Raymond W. Ko c7f2a2ab6b Fix eval with trailing comment in nREPL adapter 2013-01-09 00:13:21 -05:00
Tim Pope 058da0d71c Account for long ns doc strings 2013-01-09 00:07:24 -05:00
Tim Pope fbfc6e09b4 Load stack traces into location list.
Closes #20.
2013-01-07 22:41:04 -05:00
Tim Pope 84168b7c5e Monkey patch to support zip files in quickfix 2013-01-07 22:32:57 -05:00
Tim Pope 6c2e33f715 Fix gilardi scenario 2013-01-07 18:58:01 -05:00
Tim Pope be964782b8 Remove half baked crap 2013-01-07 01:55:08 -05:00
Tim Pope 528cb5b01a Capture nREPL stack trace 2013-01-07 01:51:48 -05:00
Tim Pope 0ff9cd710d Tighten error handling of lein autoconnect
Fixes #28.
2013-01-06 23:18:15 -05:00
Tim Pope 3ee902f648 Fix one-off runner
Closes #29.
2013-01-06 20:54:42 -05:00
Tim Pope 0d96405c1f Promote classpath.vim
The included version is going away.  Let's start getting people to
install it.
2013-01-06 20:19:16 -05:00
Tim Pope 4c60151330 Bring $JAVA_CMD inline 2013-01-06 19:53:37 -05:00
Tim Pope 8ad87d4fba Remove specialized shell escape function
The cases this was guarding against aren't actually relevant any more.
2013-01-06 19:04:06 -05:00
Raymond W. Ko fc5167b939 Update documentation to reflect Python addition 2013-01-06 18:59:32 -05:00
Raymond W. Ko 9d64e45d8d Add option of using if_python if if_ruby is not available 2013-01-06 18:58:19 -05:00
Tim Pope fe8277b42f Extract classpath.vim to a separate plugin
Keeping it in the repository, for now.  Disable it with

	let g:no_foreplay_classpath = 1

This eliminates the startup delay at the cost of requiring a REPL to
evaluate code.

References #3.
2013-01-06 18:00:06 -05:00
Tim Pope 113bc5487f Clarify header of nrepl autoload file 2013-01-06 18:00:06 -05:00
Tim Pope f4a1c5a5fe Fix jump to top of file after cqp 2013-01-05 19:54:30 -05:00
Tim Pope fbc0c54548 Provide and use foreplay#evalprint()
This provides a central point for alternate output methods, such as
capturing to a buffer.

In support of #7.
2013-01-05 00:08:36 -05:00
Tim Pope e62540fef9 Separate user from system evals
This keeps the user's session clean by not using it for things the user
did not directly dispatch (such as omnicomplete).  On the fence but
currently included in the user session is commands like :Doc.
2013-01-05 00:08:32 -05:00
Tim Pope 39d1e296cf Defend against broken g:FOREPLAY_HISTORY
Closes #26.
2013-01-04 09:35:32 -05:00
Tim Pope 3ff1633daa Make client responsible for knowing class path 2013-01-03 19:10:38 -05:00
Tim Pope 3fa8d8396f Better extraction of ns form
Goal: not require class path at all.
2013-01-03 18:45:30 -05:00
Tim Pope 1d51636fa1 Enforce viminfo+=!
Hypothesis: people complaining about startup time aren't even trying
this.
2013-01-03 13:11:15 -05:00
Tim Pope 77c0166262 Add <Plug> maps for everything 2013-01-03 00:10:11 -05:00
Tim Pope 1fa30f77eb Don't rely on iskeyword to determine namespace
Workaround for #24 and #25.
2013-01-02 19:09:53 -05:00
Tim Pope 5e0d266ae4 Catch more connection errors 2013-01-01 20:15:02 -05:00
Tim Pope 5213b65b97 Fix :Apropos 2013-01-01 20:09:16 -05:00
Tim Pope 8757e41cf3 Fix potential \r in Windows target/repl-port file 2013-01-01 20:06:14 -05:00
Tim Pope b21e531998 Don't hang on connecting to lein 1.7's REPL 2012-12-31 20:41:04 -05:00
Tim Pope 36bc4baa61 Really fix classpath detection on Windows 2012-12-31 20:35:23 -05:00
Tim Pope 8fc624b04e Fix classpath detection on Windows 2012-12-31 20:22:18 -05:00
Tim Pope a31c98c9ef Properly escape temp paths on Windows
This was leading to a cryptic error message referencing \U (as in
"C:\Users").  Addresses half of #22.
2012-12-31 19:54:46 -05:00
13 changed files with 2586 additions and 1529 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/doc/tags /doc/tags
*.pyc

10
CONTRIBUTING.markdown Normal file
View File

@ -0,0 +1,10 @@
## Contributing
Open [GitHub issues][] for bug reports and feature requests.
I'm a stickler for [commit messages][], so if you send me a pull
request with so much as superfluous period in the subject line, I will
reject it, then TP your house.
[GitHub issues]: http://github.com/tpope/vim-fireplace/issues
[commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html

View File

@ -1,24 +1,27 @@
# foreplay.vim # fireplace.vim
There's a REPL in foreplay, but you probably wouldn't have noticed if I hadn't There's a REPL in fireplace, but you probably wouldn't have noticed if I hadn't
told you. Such is the way with foreplay.vim. By the way, this plugin is for told you. Such is the way with fireplace.vim. By the way, this plugin is for
Clojure. Clojure.
## Installation ## Installation
Foreplay.vim doesn't provide indenting or syntax highlighting, so you'll want First, set up [cider-nrepl][]. (If you skip this step, fireplace.vim will
[a set of Clojure runtime files](https://github.com/guns/vim-clojure-static). make do with eval, which mostly works.) Next, fireplace.vim doesn't provide
indenting or syntax highlighting, so you'll want [a set of Clojure runtime
files](https://github.com/guns/vim-clojure-static) if you're on a version of
Vim earlier than 7.4. You might also want [salve.vim][] for assorted
static project support.
If you don't have a preferred installation method, I recommend If you don't have a preferred installation method, I recommend
installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and
then simply copy and paste: then simply copy and paste:
cd ~/.vim/bundle cd ~/.vim/bundle
git clone git://github.com/tpope/vim-foreplay.git git clone git://github.com/tpope/vim-fireplace.git
git clone git://github.com/guns/vim-clojure-static.git
Once help tags have been generated, you can view the manual with Once help tags have been generated, you can view the manual with
`:help foreplay`. `:help fireplace`.
## Features ## Features
@ -26,17 +29,25 @@ This list isn't exhaustive; see the `:help` for details.
### Transparent setup ### Transparent setup
Foreplay.vim talks to nREPL. With Leiningen 2, it connects automatically Fireplace.vim talks to nREPL. With Leiningen, it connects automatically based
based on `target/repl-port`, otherwise it's just a `:Connect` away. You can on `.nrepl-port`, otherwise it's just a `:Connect` away. You can connect to
connect to multiple instances of nREPL for different projects, and it will multiple instances of nREPL for different projects, and it will use the right
use the right one automatically. one automatically. ClojureScript support is just as seamless with
[Piggieback][].
The only external dependency is that you have Ruby installed. The only external dependency is that you have either a Vim with Python support
compiled in, or `python` in your path.
Oh, and if you don't have an nREPL connection, it falls back to using Oh, and if you don't have an nREPL connection, installing [salve.vim][]
`java clojure.main`, using a class path based on your Leiningen or Maven lets it fall back to using `java clojure.main` for some of the basics, using a
config. It's a bit slow, but a two second delay its vastly preferable to class path based on your Leiningen config. It's a bit slow, but a two-second
being forced out of my flow for a single command, in my book. delay is vastly preferable to being forced out of my flow for a single
command, in my book.
[cider-nrepl]: https://github.com/clojure-emacs/cider-nrepl
[Piggieback]: https://github.com/cemerick/piggieback
[classpath.vim]: https://github.com/tpope/vim-classpath
[salve.vim]: https://github.com/tpope/vim-salve
### Not quite a REPL ### Not quite a REPL
@ -45,7 +56,7 @@ absolutely flawlessly, never breaking just because you did something innocuous
like backspace through part of the prompt? No? Such a shame, you really like backspace through part of the prompt? No? Such a shame, you really
would have liked it. would have liked it.
I've taken a different approach in foreplay.vim. `cq` (Think "Clojure I've taken a different approach in fireplace.vim. `cq` (Think "Clojure
Quasi-REPL") is the prefix for a set of commands that bring up a *command-line Quasi-REPL") is the prefix for a set of commands that bring up a *command-line
window* — the same thing you get when you hit `q:` — but set up for Clojure window* — the same thing you get when you hit `q:` — but set up for Clojure
code. code.
@ -57,15 +68,24 @@ cursor. `cqc` gives you a blank line in insert mode.
Standard stuff here. `:Eval` evaluates a range (`:%Eval` gets the whole Standard stuff here. `:Eval` evaluates a range (`:%Eval` gets the whole
file), `:Require` requires a namespace with `:reload` (`:Require!` does file), `:Require` requires a namespace with `:reload` (`:Require!` does
`:reload-all`), either the current buffer or a given argument. There's a `cp` `:reload-all`), either the current buffer or a given argument. `:RunTests`
operator that evaluates a given motion (`cpp` for the expression under the kicks off `(clojure.test/run-tests)` and loads the results into the quickfix
cursor). list.
There's a `cp` operator that evaluates a given motion (`cpp` for the
innermost form under the cursor). `cm` and `c1m` are similar, but they only
run `clojure.walk/macroexpand-all` and `macroexpand-1` instead of evaluating
the form entirely.
Any failed evaluation loads the stack trace into the location list, which
can be easily accessed with `:lopen`.
### Navigating and Comprehending ### Navigating and Comprehending
I'm new to Clojure, so stuff that helps me understand code is a top priority. I was brand new to Clojure when I started this plugin, so stuff that helped me
understand code was a top priority.
* `:Source`, `:Doc`, `:FindDoc`, and `:Apropros`, which map to the underlying * `:Source`, `:Doc`, and `:FindDoc`, which map to the underlying
`clojure.repl` macro (with tab complete, of course). `clojure.repl` macro (with tab complete, of course).
* `K` is mapped to look up the symbol under the cursor with `doc`. * `K` is mapped to look up the symbol under the cursor with `doc`.
@ -84,47 +104,17 @@ Where possible, I favor enhancing built-ins over inventing a bunch of
Because why not? It works in the quasi-REPL too. Because why not? It works in the quasi-REPL too.
### FAQ ## FAQ
> Why does it take so long for Vim to startup? > Why does it take so long for Vim to startup?
The short answer is because the JVM is slow. That's either [classpath.vim][] or [salve.vim][].
The first time you load a Clojure file from any given project, foreplay.vim
sets about trying to determine your class path, leveraging either
`lein classpath` or `mvn dependency:build-classpath`. This takes a couple of
seconds or so in the best case scenario, and potentially much longer if it
decides to hit the network. (I don't understand why "tell me the class path"
requires hitting the network, but what do I know?)
Because the class path is oh-so-expensive to retrieve, foreplay.vim caches it
in `g:CLASSPATH_CACHE`. By default, this disappears when you exit Vim, but
you can save it across sessions in `.viminfo` with this handy option:
set viminfo+=!
The cache is expired when the timestamp on `project.clj` or `pom.xml` changes.
## Contributing
More than any other plugin, I'm in over my head here. I tried to do my
homework, but you don't learn best practices overnight. Please, open
[GitHub issues][] for bug reports and feature requests. Even better than a
feature request is just to tell me the pain you're experiencing, and perhaps
some ideas for what might eliminate it. I know Vimscript; you know Clojure.
Let's synergize.
I'm a stickler for [commit messages][], so if you send me a pull
request with so much as superfluous period in the subject line, I will
reject it, then TP your house.
[GitHub issues]: http://github.com/tpope/vim-foreplay/issues
[commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
## Self-Promotion ## Self-Promotion
Like foreplay.vim? Follow the repository on Like fireplace.vim? Follow the repository on
[GitHub](https://github.com/tpope/vim-foreplay). And if [GitHub](https://github.com/tpope/vim-fireplace) and vote for it on
[vim.org](http://www.vim.org/scripts/script.php?script_id=4978). And if
you're feeling especially charitable, follow [tpope](http://tpo.pe/) on you're feeling especially charitable, follow [tpope](http://tpo.pe/) on
[Twitter](http://twitter.com/tpope) and [Twitter](http://twitter.com/tpope) and
[GitHub](https://github.com/tpope). [GitHub](https://github.com/tpope).

View File

@ -1,126 +0,0 @@
" classpath.vim - Manipulate the Java class path
" Maintainer: Tim Pope <http://tpo.pe>
if exists("g:autoloaded_classpath")
finish
endif
let g:autoloaded_classpath = 1
function! classpath#separator() abort
return has('win32') ? ';' : ':'
endfunction
function! classpath#file_separator() abort
return exists('shellslash') && !&shellslash ? '\' : '/'
endfunction
function! classpath#split(cp) abort
return split(a:cp, classpath#separator())
endfunction
function! classpath#to_vim(cp) abort
let path = []
for elem in classpath#split(a:cp)
let path += [elem ==# '.' ? '' : elem]
endfor
if a:cp =~# '\(^\|:\)\.$'
let path += ['']
endif
return join(map(path, 'escape(v:val, ", ")'), ',')
endfunction
function! classpath#from_vim(path) abort
if a:path =~# '^,\=$'
return '.'
endif
let path = []
for elem in split(substitute(a:path, ',$', '', ''), ',')
if elem ==# ''
let path += ['.']
else
let path += split(glob(substitute(elem, '\\\ze[\\ ,]', '', 'g'), 1), "\n")
endif
endfor
return join(path, classpath#separator())
endfunction
function! classpath#detect(...) abort
let sep = classpath#file_separator()
let buffer = a:0 ? a:1 : '%'
let default = $CLASSPATH ==# '' ? ',' : classpath#to_vim($CLASSPATH)
let root = getbufvar(buffer, 'java_root')
if root ==# ''
let root = simplify(fnamemodify(bufname(buffer), ':p:s?[\/]$??'))
endif
if !isdirectory(fnamemodify(root, ':h'))
return default
endif
let previous = ""
while root !=# previous
if isdirectory(root . '/src')
if filereadable(root . '/project.clj')
let file = 'project.clj'
let cmd = 'lein classpath'
let pattern = "[^\n]*\\ze\n*$"
let default = join(map(['test', 'src', 'dev-resources', 'resources', 'target'.sep.'classes'], 'escape(root . sep . v:val, ", ")'), ',')
let base = ''
break
endif
if filereadable(root . '/pom.xml')
let file = 'pom.xml'
let cmd = 'mvn dependency:build-classpath'
let pattern = '\%(^\|\n\)\zs[^[].\{-\}\ze\n'
let base = escape(root.sep.'src'.sep.'*'.sep.'*', ', ') . ','
let default = base . default
break
endif
endif
let previous = root
let root = fnamemodify(root, ':h')
endwhile
if !exists('file')
if a:0 > 1 && a:2 ==# 'keep'
return ''
else
return default
endif
endif
if !exists('g:CLASSPATH_CACHE') || type(g:CLASSPATH_CACHE) != type({})
unlet! g:CLASSPATH_CACHE
let g:CLASSPATH_CACHE = {}
endif
let [when, last, path] = split(get(g:CLASSPATH_CACHE, root, "-1\t-1\t."), "\t")
let disk = getftime(root . sep . file)
if last ==# disk
return path
else
try
if &verbose
echomsg 'Determining class path with '.cmd.' ...'
endif
let out = system('cd ' . shellescape(root) . ' && ' . cmd)
catch /^Vim:Interrupt/
return default
endtry
let match = matchstr(out, pattern)
if !v:shell_error && exists('out') && out !=# ''
let path = base . classpath#to_vim(match)
let g:CLASSPATH_CACHE[root] = localtime() . "\t" . disk . "\t" . path
return path
else
echohl WarningMSG
echomsg "Couldn't determine class path."
echohl NONE
echo out
return default
endif
endif
endfunction
" vim:set et sw=2:

View File

@ -0,0 +1,263 @@
" Location: autoload/nrepl/fireplace.vim
if exists("g:autoloaded_fireplace_nrepl")
finish
endif
let g:autoloaded_fireplace_nrepl = 1
function! s:function(name) abort
return function(substitute(a:name,'^s:',matchstr(expand('<sfile>'), '<SNR>\d\+_'),''))
endfunction
if !exists('s:id')
let s:vim_id = localtime()
let s:id = 0
endif
function! fireplace#nrepl#next_id() abort
let s:id += 1
return 'fireplace-'.hostname().'-'.s:vim_id.'-'.s:id
endfunction
if !exists('g:fireplace_nrepl_sessions')
let g:fireplace_nrepl_sessions = {}
endif
augroup fireplace_nrepl_connection
autocmd!
autocmd VimLeave * for s:session in values(g:fireplace_nrepl_sessions)
\ | call s:session.close()
\ | endfor
augroup END
function! fireplace#nrepl#for(transport) abort
let client = copy(s:nrepl)
let client.transport = a:transport
let client.session = client.process({'op': 'clone', 'session': 0})['new-session']
let client.describe = client.process({'op': 'describe', 'verbose?': 1})
if get(client.describe.versions.nrepl, 'major', -1) == 0 &&
\ client.describe.versions.nrepl.minor < 2
throw 'nREPL: 0.2.0 or higher required'
endif
" Handle boot, which sets a fake.class.path entry
let response = client.process({'op': 'eval', 'code':
\ '[(System/getProperty "path.separator") (System/getProperty "fake.class.path")]', 'session': ''})
let cpath = response.value[-1][5:-2]
if cpath !=# 'nil'
let cpath = eval(cpath)
if !empty(cpath)
let client._path = split(cpath, response.value[-1][2])
endif
endif
if !has_key(client, '_path') && client.has_op('classpath')
let response = client.message({'op': 'classpath'})[0]
if type(get(response, 'classpath')) == type([])
let client._path = response.classpath
endif
endif
if !has_key(client, '_path')
let response = client.process({'op': 'eval', 'code':
\ '[(System/getProperty "path.separator") (System/getProperty "java.class.path")]', 'session': ''})
let client._path = split(eval(response.value[-1][5:-2]), response.value[-1][2])
endif
let g:fireplace_nrepl_sessions[client.session] = client
return client
endfunction
function! s:nrepl_close() dict abort
if has_key(self, 'session')
try
unlet! g:fireplace_nrepl_sessions[self.session]
call self.message({'op': 'close'}, 'ignore')
catch
finally
unlet self.session
endtry
endif
call self.transport.close()
return self
endfunction
function! s:nrepl_clone() dict abort
let client = copy(self)
if has_key(self, 'session')
let client.session = client.process({'op': 'clone'})['new-session']
let g:fireplace_nrepl_sessions[client.session] = client
endif
return client
endfunction
function! s:nrepl_path() dict abort
return self._path
endfunction
function! fireplace#nrepl#combine(responses)
let combined = {'status': [], 'session': []}
for response in a:responses
for key in keys(response)
if key ==# 'id' || key ==# 'ns'
let combined[key] = response[key]
elseif key ==# 'value'
let combined.value = extend(get(combined, 'value', []), [response.value])
elseif key ==# 'status'
for entry in response[key]
if index(combined[key], entry) < 0
call extend(combined[key], [entry])
endif
endfor
elseif key ==# 'session'
if index(combined[key], response[key]) < 0
call extend(combined[key], [response[key]])
endif
elseif type(response[key]) == type('')
let combined[key] = get(combined, key, '') . response[key]
else
let combined[key] = response[key]
endif
endfor
endfor
return combined
endfunction
function! s:nrepl_process(msg) dict abort
let combined = fireplace#nrepl#combine(self.message(a:msg))
if index(combined.status, 'error') < 0
return combined
endif
throw 'nREPL: ' . tr(combined.status[0], '-', ' ')
endfunction
function! s:nrepl_eval(expr, ...) dict abort
let msg = {"op": "eval"}
let msg.code = a:expr
let options = a:0 ? a:1 : {}
if has_key(options, 'ns')
let msg.ns = options.ns
elseif has_key(self, 'ns')
let msg.ns = self.ns
endif
if has_key(options, 'session')
let msg.session = options.session
endif
if has_key(options, 'id')
let msg.id = options.id
else
let msg.id = fireplace#nrepl#next_id()
endif
if has_key(options, 'file_path')
let msg.op = 'load-file'
let msg['file-path'] = options.file_path
let msg['file-name'] = fnamemodify(options.file_path, ':t')
if has_key(msg, 'ns')
let msg.file = "(in-ns '".msg.ns.") ".msg.code
call remove(msg, 'ns')
else
let msg.file = msg.code
endif
call remove(msg, 'code')
endif
try
let response = self.process(msg)
finally
if !exists('response')
let session = get(msg, 'session', self.session)
if !empty(session)
call self.message({'op': 'interrupt', 'session': session, 'interrupt-id': msg.id}, 'ignore')
endif
throw 'Clojure: Interrupt'
endif
endtry
if has_key(response, 'ns') && empty(get(options, 'ns'))
let self.ns = response.ns
endif
if has_key(response, 'ex') && !empty(get(msg, 'session', 1))
let response.stacktrace = s:extract_last_stacktrace(self, get(msg, 'session', self.session))
endif
if has_key(response, 'value')
let response.value = response.value[-1]
endif
return response
endfunction
function! s:extract_last_stacktrace(nrepl, session) abort
if a:nrepl.has_op('stacktrace')
let stacktrace = a:nrepl.message({'op': 'stacktrace', 'session': a:session})
if len(stacktrace) > 0 && has_key(stacktrace[0], 'stacktrace')
let stacktrace = stacktrace[0].stacktrace
endif
call filter(stacktrace, 'has_key(v:val, "file")')
if !empty(stacktrace)
return map(stacktrace, 'v:val.class.".".v:val.method."(".v:val.file.":".v:val.line.")"')
endif
endif
let format_st = '(symbol (str "\n\b" (apply str (interleave (repeat "\n") (map str (.getStackTrace *e)))) "\n\b\n"))'
let response = a:nrepl.process({'op': 'eval', 'code': '['.format_st.' *3 *2 *1]', 'ns': 'user', 'session': a:session})
try
let stacktrace = split(get(split(response.value[0], "\n\b\n"), 1, ""), "\n")
catch
throw string(response)
endtry
call a:nrepl.message({'op': 'eval', 'code': '(*1 1)', 'ns': 'user', 'session': a:session})
call a:nrepl.message({'op': 'eval', 'code': '(*2 2)', 'ns': 'user', 'session': a:session})
call a:nrepl.message({'op': 'eval', 'code': '(*3 3)', 'ns': 'user', 'session': a:session})
return stacktrace
endfunction
let s:keepalive = tempname()
call writefile([getpid()], s:keepalive)
function! s:nrepl_prepare(msg) dict abort
let msg = copy(a:msg)
if !has_key(msg, 'id')
let msg.id = fireplace#nrepl#next_id()
endif
if empty(get(msg, 'ns', 1))
unlet msg.ns
endif
if empty(get(msg, 'session', 1))
unlet msg.session
elseif !has_key(msg, 'session')
let msg.session = self.session
endif
return msg
endfunction
function! fireplace#nrepl#callback(body, type, callback) abort
try
let response = {'body': a:body, 'type': a:type}
if has_key(g:fireplace_nrepl_sessions, get(a:body, 'session'))
let response.session = g:fireplace_nrepl_sessions[a:body.session]
endif
call call(a:callback[0], [response] + a:callback[1:-1])
catch
endtry
endfunction
function! s:nrepl_call(msg, ...) dict abort
let terms = a:0 ? a:1 : ['done']
let sels = a:0 > 1 ? a:2 : {}
return call(self.transport.call, [a:msg, terms, sels] + a:000[2:-1], self.transport)
endfunction
function! s:nrepl_message(msg, ...) dict abort
let msg = self.prepare(a:msg)
let sel = {'id': msg.id}
return call(self.call, [msg, ['done'], sel] + a:000, self)
endfunction
function! s:nrepl_has_op(op) dict abort
return has_key(self.describe.ops, a:op)
endfunction
let s:nrepl = {
\ 'close': s:function('s:nrepl_close'),
\ 'clone': s:function('s:nrepl_clone'),
\ 'prepare': s:function('s:nrepl_prepare'),
\ 'call': s:function('s:nrepl_call'),
\ 'message': s:function('s:nrepl_message'),
\ 'eval': s:function('s:nrepl_eval'),
\ 'has_op': s:function('s:nrepl_has_op'),
\ 'path': s:function('s:nrepl_path'),
\ 'process': s:function('s:nrepl_process')}

View File

@ -0,0 +1,156 @@
" Location: autoload/nrepl/fireplace_connection.vim
if exists("g:autoloaded_nrepl_fireplace_connection") || &cp
finish
endif
let g:autoloaded_nrepl_fireplace_connection = 1
let s:python_dir = fnamemodify(expand("<sfile>"), ':p:h:h:h') . '/python'
function! s:function(name) abort
return function(substitute(a:name,'^s:',matchstr(expand('<sfile>'), '<SNR>\d\+_'),''))
endfunction
" Bencode {{{1
function! fireplace#nrepl_connection#bencode(value) abort
if type(a:value) == type(0)
return 'i'.a:value.'e'
elseif type(a:value) == type('')
return strlen(a:value).':'.a:value
elseif type(a:value) == type([])
return 'l'.join(map(copy(a:value),'fireplace#nrepl_connection#bencode(v:val)'),'').'e'
elseif type(a:value) == type({})
return 'd'.join(map(
\ sort(keys(a:value)),
\ 'fireplace#nrepl_connection#bencode(v:val) . ' .
\ 'fireplace#nrepl_connection#bencode(a:value[v:val])'
\ ),'').'e'
else
throw "Can't bencode ".string(a:value)
endif
endfunction
" }}}1
function! s:shellesc(arg) abort
if a:arg =~ '^[A-Za-z0-9_/.-]\+$'
return a:arg
elseif &shell =~# 'cmd'
throw 'Python interface not working. See :help python-dynamic'
else
let escaped = shellescape(a:arg)
if &shell =~# 'sh' && &shell !~# 'csh'
return substitute(escaped, '\\\n', '\n', 'g')
else
return escaped
endif
endif
endfunction
if !exists('s:id')
let s:vim_id = localtime()
let s:id = 0
endif
function! s:id() abort
let s:id += 1
return 'fireplace-'.hostname().'-'.s:vim_id.'-'.s:id
endfunction
function! fireplace#nrepl_connection#prompt() abort
return fireplace#input_host_port()
endfunction
function! fireplace#nrepl_connection#open(arg) abort
if a:arg =~# '^\d\+$'
let host = 'localhost'
let port = a:arg
elseif a:arg =~# ':\d\+$'
let host = matchstr(a:arg, '.*\ze:')
let port = matchstr(a:arg, ':\zs.*')
else
throw "nREPL: Couldn't find [host:]port in " . a:arg
endif
let transport = deepcopy(s:nrepl_transport)
let transport.host = host
let transport.port = port
return fireplace#nrepl#for(transport)
endfunction
function! s:nrepl_transport_close() dict abort
return self
endfunction
let s:keepalive = tempname()
call writefile([getpid()], s:keepalive)
function! s:nrepl_transport_command(cmd, args) dict abort
return 'python'
\ . ' ' . s:shellesc(s:python_dir.'/nrepl_fireplace.py')
\ . ' ' . s:shellesc(self.host)
\ . ' ' . s:shellesc(self.port)
\ . ' ' . s:shellesc(s:keepalive)
\ . ' ' . s:shellesc(a:cmd)
\ . ' ' . join(map(copy(a:args), 's:shellesc(fireplace#nrepl_connection#bencode(v:val))'), ' ')
endfunction
function! s:nrepl_transport_dispatch(cmd, ...) dict abort
let in = self.command(a:cmd, a:000)
let out = system(in)
if !v:shell_error
return eval(out)
endif
throw 'nREPL: '.out
endfunction
function! s:nrepl_transport_call(msg, terms, sels, ...) dict abort
let payload = fireplace#nrepl_connection#bencode(a:msg)
let response = self.dispatch('call', payload, a:terms, a:sels)
if !a:0
return response
elseif a:1 !=# 'ignore'
return map(response, 'fireplace#nrepl#callback(v:val, "synchronous", a:000)')
endif
endfunction
let s:nrepl_transport = {
\ 'close': s:function('s:nrepl_transport_close'),
\ 'command': s:function('s:nrepl_transport_command'),
\ 'dispatch': s:function('s:nrepl_transport_dispatch'),
\ 'call': s:function('s:nrepl_transport_call')}
if !has('python') || $FIREPLACE_NO_IF_PYTHON
finish
endif
if !exists('s:python')
exe 'python sys.path.insert(0, "'.escape(s:python_dir, '\"').'")'
let s:python = 1
python import nrepl_fireplace
else
python reload(nrepl_fireplace)
endif
python << EOF
import vim
def fireplace_let(var, value):
return vim.command('let ' + var + ' = ' + nrepl_fireplace.vim_encode(value))
def fireplace_check():
vim.eval('getchar(1)')
def fireplace_repl_dispatch(command, *args):
try:
fireplace_let('out', nrepl_fireplace.dispatch(vim.eval('self.host'), vim.eval('self.port'), fireplace_check, None, command, *args))
except Exception, e:
fireplace_let('err', str(e))
EOF
function! s:nrepl_transport_dispatch(command, ...) dict abort
python fireplace_repl_dispatch(vim.eval('a:command'), *vim.eval('a:000'))
if !exists('err')
return out
endif
throw 'nREPL Connection Error: '.err
endfunction

View File

@ -1,232 +0,0 @@
" nrepl/foreplay_connection.vim
" Maintainer: Tim Pope <http://tpo.pe/>
if exists("g:autoloaded_nrepl_foreplay_connection") || &cp
finish
endif
let g:autoloaded_nrepl_foreplay_connection = 1
function! s:function(name) abort
return function(substitute(a:name,'^s:',matchstr(expand('<sfile>'), '<SNR>\d\+_'),''))
endfunction
" Bencode {{{1
function! nrepl#foreplay_connection#bencode(value) abort
if type(a:value) == type(0)
return 'i'.a:value.'e'
elseif type(a:value) == type('')
return strlen(a:value).':'.a:value
elseif type(a:value) == type([])
return 'l'.join(map(a:value,'nrepl#foreplay_connection#bencode(v:val)'),'').'e'
elseif type(a:value) == type({})
return 'd'.join(values(map(a:value,'nrepl#foreplay_connection#bencode(v:key).nrepl#foreplay_connection#bencode(v:val)')),'').'e'
else
throw "Can't bencode ".string(a:value)
endif
endfunction
function! nrepl#foreplay_connection#bdecode(value) abort
return s:bdecode({'pos': 0, 'value': a:value})
endfunction
function! s:bdecode(state) abort
let value = a:state.value
if value[a:state.pos] =~# '\d'
let pos = a:state.pos
let length = matchstr(value[pos : -1], '^\d\+')
let a:state.pos += strlen(length) + length + 1
return value[pos+strlen(length)+1 : pos+strlen(length)+length]
elseif value[a:state.pos] ==# 'i'
let int = matchstr(value[a:state.pos+1:-1], '[^e]*')
let a:state.pos += 2 + strlen(int)
return str2nr(int)
elseif value[a:state.pos] ==# 'l'
let values = []
let a:state.pos += 1
while value[a:state.pos] !=# 'e' && value[a:state.pos] !=# ''
call add(values, s:bdecode(a:state))
endwhile
let a:state.pos += 1
return values
elseif value[a:state.pos] ==# 'd'
let values = {}
let a:state.pos += 1
while value[a:state.pos] !=# 'e' && value[a:state.pos] !=# ''
let key = s:bdecode(a:state)
let values[key] = s:bdecode(a:state)
endwhile
let a:state.pos += 1
return values
else
throw 'bencode parse error: '.string(a:state)
endif
endfunction
" }}}1
function! s:shellesc(arg) abort
if a:arg =~ '^[A-Za-z0-9_/.-]\+$'
return a:arg
elseif &shell =~# 'cmd'
return '"'.substitute(substitute(a:arg, '"', '""', 'g'), '%', '"%"', 'g').'"'
else
let escaped = shellescape(a:arg)
if &shell =~# 'sh' && &shell !~# 'csh'
return substitute(escaped, '\\\n', '\n', 'g')
else
return escaped
endif
endif
endfunction
function! nrepl#foreplay_connection#prompt() abort
return foreplay#input_host_port()
endfunction
function! nrepl#foreplay_connection#open(arg) abort
if a:arg =~# '^\d\+$'
let host = 'localhost'
let port = a:arg
elseif a:arg =~# ':\d\+$'
let host = matchstr(a:arg, '.*\ze:')
let port = matchstr(a:arg, ':\zs.*')
else
throw "nREPL: Couldn't find [host:]port in " . a:arg
endif
let client = deepcopy(s:nrepl)
let client.host = host
let client.port = port
let session = client.process({'op': 'clone'})['new-session']
let response = client.process({'op': 'eval', 'session': session, 'code':
\ '(do (println "success") (symbol (str (System/getProperty "path.separator") (System/getProperty "java.class.path"))))'})
let client._path = response.value[-1]
if has_key(response, 'out')
let client.session = session
endif
return client
endfunction
function! s:nrepl_path() dict abort
return split(self._path[1:-1], self._path[0])
endfunction
function! s:nrepl_process(payload) dict abort
let combined = {'status': [], 'session': []}
for response in self.call(a:payload)
for key in keys(response)
if key ==# 'id' || key ==# 'ns'
let combined[key] = response[key]
elseif key ==# 'value'
let combined.value = extend(get(combined, 'value', []), [response.value])
elseif key ==# 'status'
for entry in response[key]
if index(combined[key], entry) < 0
call extend(combined[key], [entry])
endif
endfor
elseif key ==# 'session'
if index(combined[key], response[key]) < 0
call extend(combined[key], [response[key]])
endif
elseif type(response[key]) == type('')
let combined[key] = get(combined, key, '') . response[key]
else
let combined[key] = response[key]
endif
endfor
endfor
if index(combined.status, 'error') >= 0
throw 'nREPL: ' . tr(combined.status[0], '-', ' ')
endif
return combined
endfunction
function! s:nrepl_eval(expr, ...) dict abort
let payload = {"op": "eval", "code": a:expr}
if a:0
let payload.ns = a:1
elseif has_key(self, 'ns')
let payload.ns = self.ns
endif
if has_key(self, 'session')
let payload.session = self.session
endif
let response = self.process(payload)
if has_key(response, 'ns') && !a:0
let self.ns = response.ns
endif
if has_key(response, 'value')
let response.value = response.value[-1]
endif
return response
endfunction
function! s:nrepl_call(payload) dict abort
let in = 'ruby -rsocket -e '.s:shellesc(
\ 'begin;' .
\ 'TCPSocket.open(%(' . self.host . '), ' . self.port . ') {|s|' .
\ 's.write(ARGV.first); loop {' .
\ 'body = s.readpartial(8192); print body;' .
\ 'break if body.include?(%(6:statusl4:done)) }};' .
\ 'rescue; abort $!.to_s;' .
\ 'end') . ' ' .
\ s:shellesc(nrepl#foreplay_connection#bencode(a:payload))
let out = system(in)
if !v:shell_error
return nrepl#foreplay_connection#bdecode('l'.out.'e')
endif
throw 'nREPL: '.split(out, "\n")[0]
endfunction
let s:nrepl = {
\ 'call': s:function('s:nrepl_call'),
\ 'eval': s:function('s:nrepl_eval'),
\ 'path': s:function('s:nrepl_path'),
\ 'process': s:function('s:nrepl_process')}
if !has('ruby')
finish
endif
ruby <<
require 'timeout'
require 'socket'
class << ::VIM
def string_encode(str)
'"' + str.gsub(/[\000-\037"\\]/) { |x| "\\%03o" % (x.respond_to?(:ord) ? x.ord : x[0]) } + '"'
end
def let(var, value)
command("let #{var} = #{string_encode(value)}")
end
end
.
function! s:nrepl_call(payload) dict abort
let payload = nrepl#foreplay_connection#bencode(a:payload)
ruby <<
begin
buffer = ''
Timeout.timeout(16) do
TCPSocket.open(::VIM.evaluate('self.host'), ::VIM.evaluate('self.port').to_i) do |s|
s.write(::VIM.evaluate('payload'))
loop do
body = s.readpartial(8192)
buffer << body
break if body.include?("6:statusl4:done")
end
::VIM.let('out', buffer)
end
end
rescue
::VIM.let('err', $!.to_s)
end
.
if !exists('err')
return nrepl#foreplay_connection#bdecode('l'.out.'e')
endif
throw 'nREPL: '.err
endfunction
" vim:set et sw=2:

194
doc/fireplace.txt Normal file
View File

@ -0,0 +1,194 @@
*fireplace.txt* Clojure REPL support
Author: Tim Pope <http://tpo.pe/>
License: Same terms as Vim itself (see |license|)
This plugin is only available if 'compatible' is not set.
*fireplace*
While not strictly necessary, this plugin works best with the middleware
provided by <https://github.com/clojure-emacs/cider-nrepl>.
CONNECTING TO A REPL *fireplace-connect*
Connecting to lein repl happens automatically. If you have a different setup,
you can connect by hand.
*fireplace-:Connect*
:Connect {proto}://{host}:{port} {path}
Connect to a REPL server. The path is the root of the
project that the REPL applies to.
:Connect Interactively prompt for the options to connect to a
REPL server.
The REPL is used for the commands below. If no REPL is found for the current
buffer and 'path' contains at least one jar file, java (or $JAVA_CMD) is
invoked directly, which can be quite slow depending on your setup.
The only adapter shipped with fireplace.vim is for nREPL. You need either
|if_pyth| or the python command in your PATH.
*fireplace-piggieback* *fireplace-clojurescript*
ClojureScript can be evaled with Piggieback if the appropriate nREPL
middleware is loaded: https://github.com/cemerick/piggieback. Be aware that
your ClojureScript files must be available on the classpath for this to work
properly, and that not all operations are supported.
*fireplace-:Piggieback*
:Piggieback [{env}] Create a new nREPL session and invoke
cemerick.piggieback/cljs-repl with the given or
default (Rhino) environment. This will also happen
automatically on first eval in a ClojureScript buffer
if not invoked explicitly. If {env} is a number, the
piggieback repl-env will will use a cljs.repl.browser
(rather than a Rhino) env with the port set to the
number provided.
:Piggieback! Terminate the most recently created piggieback
session.
DOCUMENTATION *fireplace-documentation*
*fireplace-:Doc*
:Doc {symbol} Show the docs for the given symbol.
*fireplace-:Javadoc*
:Javadoc {class} Open the java docs for the given class in a browser.
*fireplace-K*
K Look up docs for symbol under cursor.
*fireplace-:FindDoc*
:FindDoc {arg} Wrapper around (clojure.repl/find-doc ...).
*fireplace-:Source*
:Source {symbol} Show the source for the given symbol.
*fireplace-[d*
[d Show source for symbol under cursor.
]d
NAVIGATING *fireplace-navigating*
These commands will never use a remote REPL, only a local one, as file paths
on a remote server wouldn't be very useful locally.
*fireplace-[_CTRL-D*
[<C-D> Jump to the source of the symbol under the cursor.
]<C-D>
*fireplace-CTRL-W_CTRL-D*
<C-W><C-D> Jump to the source of the symbol under the cursor in
<C-W>d a split.
*fireplace-gf*
gf Go to the file for the namespace under the cursor.
*fireplace-:Djump*
:Djump {symbol} Jump to the definition for the given symbol.
*fireplace-:Dsplit*
:Dsplit {symbol} Jump to the definition for the given symbol in a
split.
EVALUATING CODE *fireplace-eval*
All code is evaluated in the namespace of the current file, requiring it if
necessary. If the current file sits outside the class path (project.clj, for
example), the user namespace is used instead. If an exception occurs, the
stack trace is loaded into the |location-list|. Use |:lopen| to view it.
*fireplace-:Require*
:Require [ns] Require :reload the given/current namespace.
*fireplace-:Require!*
:Require! [ns] Require :reload-all the given/current namespace.
*fireplace-:Eval*
:Eval Eval/print the outermost form for the current line.
:{range}Eval Eval/print the given range.
:Eval {expr} Eval/print the given expression.
*fireplace-:Eval!*
:[range]Eval! Eval the given range or outermost expression and
replace it with its result.
:[range]Eval! {expr} Eval the given expression and insert it after
the given range or current line.
*fireplace-:RunTests*
:RunTests [ns] [...] Call clojure.test/run-tests on the given namespaces
and load the results into the quickfix list.
:[range]RunTests Call clojure.test/test-var on the var defined at or
above the specicied line and load the results into the
quickfix list. Typically invoked as :.RunTests to run
the test under the cursor.
:0RunTests [pattern] Call clojure.test/run-all-tests with the given pattern
and load the results into the quickfix list.
*fireplace-cp*
cp{motion} Eval/print the code indicated by {motion}.
cpp Eval/print the innermost form at the cursor.
*fireplace-cpr*
cpr :Require|RunTests
*fireplace-c!*
c!{motion} Eval/replace the code indicated by {motion}.
c!! Eval/replace the innermost form at the cursor.
*fireplace-cm*
cm{motion} Fully macroexpand the code indicated by {motion}.
*fireplace-cmm*
cmm Fully macroexpand the innermost form at the cursor.
*fireplace-c1m*
c1m{motion} Macroexpand the code indicated by {motion} once.
*fireplace-c1mm*
c1mm Macroexpand the innermost form at the cursor once.
*fireplace-cqp*
cqp Bring up a prompt for code to eval/print.
*fireplace-cqq*
cqq Bring up a |command-line-window| with innermost form
at the cursor prepopulated.
*fireplace-cqc*
cqc Bring up a |command-line-window| for code to
eval/print. Equivalent to cqp<C-F>i.
*fireplace-cq*
cq{motion} Bring up a |command-line-window| with text indicated
by {motion} prepopulated.
*fireplace-:Last*
:Last Open the result of the last evaluation in the preview
window. Use :2Last to get the next-to-last result,
and so on. Once the window is open, cycle to older
and newer entries with |:lprevious| and |:lnext|.
And insert mode:
*fireplace-i_CTRL-R_(*
<C-R>( Evaluate the given expression and insert the result.
There's omnicomplete on |CTRL-X_CTRL-O|, which works in Clojure buffers and
in the |command-line-window|, and tab complete at the cqp prompt.
ABOUT *fireplace-about*
Grab the latest version or report a bug on GitHub:
http://github.com/tpope/vim-fireplace
vim:tw=78:et:ft=help:norl:

View File

@ -1,161 +0,0 @@
*foreplay.txt* Clojure REPL tease
Author: Tim Pope <http://tpo.pe/>
License: Same terms as Vim itself (see |license|)
This plugin is only available if 'compatible' is not set.
You need Clojure runtime files to use this plugin. Try VimClojure. You don't
need the interactive stuff.
CLASSPATH *foreplay-classpath*
Upon loading a Clojure buffer, the 'path' option is automatically set to your
class path. The class path is found by `lein classpath`, `mvn
dependency:build-classpath`, or failing both of those, $CLASSPATH.
Finding the class path can be slow. To cache it across multiple invocations
of Vim, try
set viminfo+=!
LEININGEN *foreplay-leiningen*
Leiningen support is currently bare bones. If a Leiningen project is found,
'makeprg' will be set to "lein".
Leiningen 2.x writes to target/repl-port when `lein repl` is invoked. If this
file is found, an nREPL connection will be established automatically.
CONNECTING TO A REPL *foreplay-connect*
*foreplay-:Connect*
:Connect {proto}://{host}:{port}
Connect to a REPL server.
:Connect Interactively prompt for the options to connect to a
REPL server.
The REPL is used for the commands below. If no REPL is found for the current
buffer, java (or $JAVA_CMD) is invoked directly (using 'path' as the class
path), which can be quite slow depending on your setup.
The only adapter shipped with foreplay.vim is for nREPL. You need Ruby
installed and either |if_ruby| or the ruby command in your PATH.
DOCUMENTATION *foreplay-documentation*
*foreplay-:Doc*
:Doc {symbol} Show the docs for the given symbol.
*foreplay-:Javadoc*
:Javadoc {class} Open the java docs for the given class in a browser.
*foreplay-K*
K Look up docs for keyword under cursor.
*foreplay-:FindDoc*
:FindDoc {arg} Wrapper around (clojure.repl/find-doc ...).
*foreplay-:Apropos*
:Apropos {arg} Wrapper around (clojure.repl/apropos ...).
*foreplay-:Source*
:Source {symbol} Show the source for the given symbol.
*foreplay-[d*
[d Show source for keyword under cursor.
]d
NAVIGATING *foreplay-navigating*
These commands will never use a remote REPL, only a local one, as file paths
on a remote server wouldn't be very useful locally.
*foreplay-[_CTRL-D*
[<C-D> Jump to the source of the keyword under the cursor.
]<C-D>
*foreplay-CTRL-W_CTRL-D*
<C-W><C-D> Jump to the source of the keyword under the cursor in
<C-W>d a split.
*foreplay-gf*
gf Go to the file for the namespace under the cursor.
*foreplay-:Djump*
:Djump {symbol} Jump to the definition for the given symbol.
*foreplay-:Dsplit*
:Dsplit {symbol} Jump to the definition for the given symbol in a
split.
EVALUATING CODE *foreplay-eval*
All code is evaluated in the namespace of the current file, requiring it if
necessary. If the current file sits outside the class path (project.clj, for
example), the user namespace is used instead.
*foreplay-:Require*
:Require [ns] Require :reload the given/current namespace.
*foreplay-:Require!*
:Require! [ns] Require :reload-all the given/current namespace.
*foreplay-:Eval*
:Eval Eval/print the outermost expression for the current
line.
:{range}Eval Eval/print the given range.
:Eval {expr} Eval/print the given expression.
*foreplay-:Eval!*
:[range]Eval! Eval the given range or outermost expression and
replace it with its result.
:[range]Eval! {expr} Eval the given expression and insert it after
the given range or current line.
*foreplay-cp*
cp{motion} Eval/print the code indicated by {motion}.
cpp Eval/print the inner-most expr at the cursor.
*foreplay-cpr*
cpr Eval a require :reload form.
*foreplay-cpR*
cpR Eval a require :reload-all form.
*foreplay-c!*
c!{motion} Eval/replace the code indicated by {motion}.
c!! Eval/replace the inner-most expr at the cusror.
*foreplay-cqp*
cqp Bring up a prompt for code to eval/print.
*foreplay-cqc*
cqc Bring up a |command-line-window| for code to
eval/print. Equivalent to cqp<C-F>i.
*foreplay-cq*
cq{motion} Bring up a |command-line-window| with text indicated
by {motion} prepopulated.
And insert mode:
*foreplay-i_CTRL-R_(*
<C-R>( Evaluate the given expression and insert the result.
There's omnicomplete on |CTRL-X_CTRL-O|, which works in Clojure buffers and
in the |command-line-window|, and tab complete at the cqp prompt.
ABOUT *foreplay-about*
Grab the latest version or report a bug on GitHub:
http://github.com/tpope/vim-foreplay
vim:tw=78:et:ft=help:norl:

1742
plugin/fireplace.vim Normal file

File diff suppressed because it is too large Load Diff

40
plugin/fireplace/zip.vim Normal file
View File

@ -0,0 +1,40 @@
" Location: plugin/fireplace/zip.vim
if exists("g:loaded_zip") || &cp || v:version >= 704
finish
endif
runtime! autoload/zip.vim
" Patched to allow loading from the quickfix list. The version that ships
" with Vim 7.4 already has this change.
fun! zip#Read(fname,mode)
" call Dfunc("zip#Read(fname<".a:fname.">,mode=".a:mode.")")
let repkeep= &report
set report=10
if has("unix")
let zipfile = substitute(a:fname,'zipfile:\(.\{-}\)::[^\\].*$','\1','')
let fname = substitute(a:fname,'zipfile:.\{-}::\([^\\].*\)$','\1','')
else
let zipfile = substitute(a:fname,'^.\{-}zipfile:\(.\{-}\)::[^\\].*$','\1','')
let fname = substitute(a:fname,'^.\{-}zipfile:.\{-}::\([^\\].*\)$','\1','')
let fname = substitute(fname, '[', '[[]', 'g')
endif
" call Decho("zipfile<".zipfile.">")
" call Decho("fname <".fname.">")
" Changes for fireplace.
let temp = tempname()
let fn = expand('%:p')
exe "sil! ! ".g:zip_unzipcmd." -p -- ".shellescape(zipfile,1)." ".shellescape(fnameescape(fname),1). ' > '.temp
silent exe 'keepalt file '.temp
silent keepjumps edit!
silent exe 'keepalt file '.fnameescape(fn)
call delete(temp)
filetype detect
" Resume regularly scheduled programming.
set nomod
endfun

View File

@ -1,952 +0,0 @@
" foreplay.vim - Clojure REPL tease
" Maintainer: Tim Pope <http://tpo.pe>
if exists("g:loaded_foreplay") || v:version < 700 || &cp
finish
endif
let g:loaded_foreplay = 1
" File type {{{1
augroup foreplay_file_type
autocmd!
autocmd BufNewFile,BufReadPost *.clj setfiletype clojure
autocmd FileType clojure
\ if expand('%:p') !~# '^zipfile:' |
\ let &l:path = classpath#detect() |
\ endif
augroup END
" }}}1
" Shell escaping {{{1
function! foreplay#shellesc(arg) abort
if a:arg =~ '^[A-Za-z0-9_/.-]\+$'
return a:arg
elseif &shell =~# 'cmd'
return '"'.substitute(substitute(a:arg, '"', '""', 'g'), '%', '"%"', 'g').'"'
else
let escaped = shellescape(a:arg)
if &shell =~# 'sh' && &shell !~# 'csh'
return substitute(escaped, '\\\n', '\n', 'g')
else
return escaped
endif
endif
endfunction
" }}}1
" Completion {{{1
let s:jar_contents = {}
function! foreplay#jar_contents(path) abort
if !has_key(s:jar_contents, a:path) && executable('zipinfo')
let s:jar_contents[a:path] = split(system('zipinfo -1 '.shellescape(a:path)), "\n")
if v:shell_error
return []
endif
endif
return copy(get(s:jar_contents, a:path, []))
endfunction
function! foreplay#eval_complete(A, L, P) abort
let prefix = matchstr(a:A, '\%(.* \|^\)\%(#\=[\[{('']\)*')
let keyword = a:A[strlen(prefix) : -1]
return sort(map(foreplay#omnicomplete(0, keyword), 'prefix . v:val.word'))
endfunction
function! foreplay#ns_complete(A, L, P) abort
let matches = []
for dir in classpath#split(classpath#from_vim(&path))
if dir =~# '\.jar$'
let files = filter(foreplay#jar_contents(dir), 'v:val =~# "\\.clj$"')
else
let files = split(glob(dir."/**/*.clj", 1), "\n")
call map(files, 'v:val[strlen(dir)+1 : -1]')
endif
let matches += files
endfor
return filter(map(matches, 's:tons(v:val)'), 'a:A ==# "" || a:A ==# v:val[0 : strlen(a:A)-1]')
endfunction
function! foreplay#omnicomplete(findstart, base) abort
if a:findstart
let line = getline('.')[0 : col('.')-2]
return col('.') - strlen(matchstr(line, '\k\+$')) - 1
else
try
let omnifier = '(fn [[k v]] (let [m (meta v)]' .
\ ' {:word k :menu (pr-str (:arglists m (symbol ""))) :info (str " " (:doc m)) :kind (if (:arglists m) "f" "v")}))'
let ns = foreplay#ns()
let [aliases, namespaces, maps] = foreplay#evalparse(
\ '[(ns-aliases '.s:qsym(ns).') (all-ns) '.
\ '(sort-by :word (map '.omnifier.' (ns-map '.s:qsym(ns).')))]')
if a:base =~# '^[^/]*/[^/]*$'
let ns = matchstr(a:base, '^.*\ze/')
let prefix = ns . '/'
let ns = get(aliases, ns, ns)
let keyword = matchstr(a:base, '.*/\zs.*')
let results = foreplay#evalparse(
\ '(sort-by :word (map '.omnifier.' (ns-publics '.s:qsym(ns).')))')
for r in results
let r.word = prefix . r.word
endfor
else
let keyword = a:base
let results = maps + map(sort(keys(aliases) + namespaces), '{"word": v:val."/", "kind": "t", "info": ""}')
endif
if type(results) == type([])
return filter(results, 'a:base ==# "" || a:base ==# v:val.word[0 : strlen(a:base)-1]')
else
return []
endif
catch /.*/
return []
endtry
endif
endfunction
augroup foreplay_completion
autocmd!
autocmd FileType clojure setlocal omnifunc=foreplay#omnicomplete
augroup END
" }}}1
" REPL client {{{1
let s:repl = {"requires": {}}
if !exists('s:repls')
let s:repls = []
let s:repl_paths = {}
endif
function! s:qsym(symbol)
if a:symbol =~# '^[[:alnum:]?*!+/=<>.:-]\+$'
return "'".a:symbol
else
return '(symbol "'.escape(a:symbol, '"').'")'
endif
endfunction
function! s:repl.eval(expr, ns) dict abort
try
let result = self.connection.eval(a:expr, a:ns)
catch /^\w\+: Connection/
call filter(s:repl_paths, 'v:val isnot self')
call filter(s:repls, 'v:val isnot self')
throw v:exception
endtry
return result
endfunction
function! s:repl.require(lib) dict abort
if a:lib !~# '^\%(user\)\=$' && !get(self.requires, a:lib, 0)
let reload = has_key(self.requires, a:lib) ? ' :reload' : ''
let self.requires[a:lib] = 0
let result = self.eval('(doto '.s:qsym(a:lib).' (require'.reload.') the-ns)', 'user')
let self.requires[a:lib] = !has_key(result, 'ex')
endif
return ''
endfunction
function! s:repl.includes_file(file) dict abort
let file = substitute(a:file, '\C^zipfile:\(.*\)::', '\1/', '')
for path in self.connection.path()
if file[0 : len(path)-1] ==? path
return 1
endif
endfor
endfunction
function! s:register_connection(conn, ...)
call insert(s:repls, extend({'connection': a:conn}, deepcopy(s:repl)))
if a:0 && a:1 !=# ''
let s:repl_paths[a:1] = s:repls[0]
endif
return s:repls[0]
endfunction
" }}}1
" :Connect {{{1
command! -bar -complete=customlist,s:connect_complete -nargs=? ForeplayConnect :exe s:Connect(<q-args>)
function! foreplay#input_host_port()
let arg = input('Host> ', 'localhost')
if arg ==# ''
return ''
endif
echo "\n"
let arg .= ':' . input('Port> ')
if arg =~# ':$'
return ''
endif
echo "\n"
return arg
endfunction
function! s:protos()
return map(split(globpath(&runtimepath, 'autoload/*/foreplay_connection.vim'), "\n"), 'fnamemodify(v:val, ":h:t")')
endfunction
function! s:connect_complete(A, L, P)
let proto = matchstr(a:A, '\w\+\ze://')
if proto ==# ''
let options = map(s:protos(), 'v:val."://"')
else
let rest = matchstr(a:A, '://\zs.*')
try
let options = {proto}#foreplay_connection#complete(rest)
catch /^Vim(let):E117/
let options = ['localhost:']
endtry
call map(options, 'proto."://".v:val')
endif
if a:A !=# ''
call filter(options, 'v:val[0 : strlen(a:A)-1] ==# a:A')
endif
return options
endfunction
function! s:Connect(arg)
if a:arg =~# '^\w\+://'
let [proto, arg] = split(a:arg, '://')
elseif a:arg !=# ''
return 'echoerr '.string('Usage: :Connect proto://...')
else
let protos = s:protos()
if empty(protos)
return 'echoerr '.string('No protocols available')
endif
let proto = s:inputlist('Protocol> ', protos)
if proto ==# ''
return
endif
redraw!
echo ':Connect'
echo 'Protocol> '.proto
let arg = {proto}#foreplay_connection#prompt()
endif
try
let connection = {proto}#foreplay_connection#open(arg)
catch /.*/
return 'echoerr '.string(v:exception)
endtry
if type(connection) !=# type({}) || empty(connection)
return ''
endif
let client = s:register_connection(connection)
echo 'Connected to '.proto.'://'.arg
let path = fnamemodify(exists('b:java_root') ? b:java_root : fnamemodify(expand('%'), ':p:s?.*\zs[\/]src[\/].*??'), ':~')
let root = input('Scope connection to: ', path, 'dir')
if root !=# ''
let s:repl_paths[fnamemodify(root, ':p:s?[\/]$??')] = client
endif
return ''
endfunction
augroup foreplay_connect
autocmd!
autocmd FileType clojure command! -bar -complete=customlist,s:connect_complete -nargs=? Connect :ForeplayConnect <args>
augroup END
" }}}1
" Java runner {{{1
if !exists('g:java_cmd')
let g:java_cmd = exists('$JAVA_CMD') ? $JAVA_CMD : 'java'
endif
let s:oneoff = {}
let s:oneoff_pr = tempname()
let s:oneoff_ex = tempname()
let s:oneoff_stk = tempname()
let s:oneoff_in = tempname()
let s:oneoff_out = tempname()
let s:oneoff_err = tempname()
function! s:oneoff.eval(expr, ns) dict abort
if &verbose
echohl WarningMSG
echomsg "No REPL found. Running java clojure.main ..."
echohl None
endif
if a:ns !=# '' && a:ns !=# 'user'
let ns = '(require '.s:qsym(a:ns).') (in-ns '.s:qsym(a:ns).') '
else
let ns = ''
endif
call writefile([], s:oneoff_pr, 'b')
call writefile([], s:oneoff_ex, 'b')
call writefile([], s:oneoff_stk, 'b')
call writefile(split('(do '.a:expr.')', "\n"), s:oneoff_in, 'b')
call writefile([], s:oneoff_out, 'b')
call writefile([], s:oneoff_err, 'b')
let command = g:java_cmd.' -cp '.shellescape(self.classpath).' clojure.main -e ' .
\ foreplay#shellesc(
\ '(binding [*out* (java.io.FileWriter. "'.s:oneoff_out.'")' .
\ ' *err* (java.io.FileWriter. "'.s:oneoff_err.'")]' .
\ ' (try' .
\ ' (require ''clojure.repl) '.ns.'(spit "'.s:oneoff_pr.'" (pr-str (eval (read-string (slurp "'.s:oneoff_in.'")))))' .
\ ' (catch Exception e' .
\ ' (spit *err* (.toString e))' .
\ ' (spit "'.s:oneoff_ex.'" (class e))' .
\ ' (spit "'.s:oneoff_stk.'" (apply str (interpose "\n" (.getStackTrace e))))))' .
\ ' nil)')
let wtf = system(command)
let result = {}
let result.value = join(readfile(s:oneoff_pr, 'b'), "\n")
let result.out = join(readfile(s:oneoff_out, 'b'), "\n")
let result.err = join(readfile(s:oneoff_err, 'b'), "\n")
let result.ex = join(readfile(s:oneoff_ex, 'b'), "\n")
let result.stacktrace = readfile(s:oneoff_stk)
call filter(result, '!empty(v:val)')
if v:shell_error && get(result, 'ex', '') ==# ''
throw 'Error running Clojure: '.wtf
else
return result
endif
endfunction
function! s:oneoff.require(symbol)
return ''
endfunction
" }}}1
" Client {{{1
function! s:client() abort
silent doautocmd User ForeplayPreConnect
let buf = exists('s:input') ? s:input : '%'
let root = simplify(fnamemodify(bufname(buf), ':p:s?[\/]$??'))
let previous = ""
while root !=# previous
if has_key(s:repl_paths, root)
return s:repl_paths[root]
endif
let previous = root
let root = fnamemodify(root, ':h')
endwhile
return foreplay#local_client(1)
endfunction
function! foreplay#client() abort
return s:client()
endfunction
function! foreplay#local_client(...)
if !a:0
silent doautocmd User ForeplayPreConnect
endif
let buf = exists('s:input') ? s:input : '%'
for repl in s:repls
if repl.includes_file(fnamemodify(bufname(buf), ':p'))
return repl
endif
endfor
let cp = classpath#from_vim(getbufvar(buf, '&path'))
return extend({'classpath': cp}, s:oneoff)
endfunction
function! foreplay#eval(expr, ...) abort
let c = s:client()
if !a:0 && foreplay#ns() !~# '^\%(user\)$'
call c.require(foreplay#ns())
endif
let result = c.eval(a:expr, a:0 ? a:1 : foreplay#ns())
if get(result, 'err', '') !=# ''
echohl ErrorMSG
echo substitute(result.err, '\n$', '', '')
echohl NONE
endif
if get(result, 'out', '') !=# ''
echo substitute(result.out, '\n$', '', '')
endif
if get(result, 'ex', '') !=# ''
let err = 'Clojure: '.result.ex
elseif has_key(result, 'value')
return result.value
else
let err = 'foreplay.vim: Something went wrong: '.string(result)
endif
throw err
endfunction
function! foreplay#evalparse(expr) abort
let body = foreplay#eval(
\ '(symbol ((fn *vimify [x]' .
\ ' (cond' .
\ ' (map? x) (str "{" (apply str (interpose ", " (map (fn [[k v]] (str (*vimify k) ": " (*vimify v))) x))) "}")' .
\ ' (coll? x) (str "[" (apply str (interpose ", " (map *vimify x))) "]")' .
\ ' (number? x) (pr-str x)' .
\ ' (keyword? x) (pr-str (name x))' .
\ ' :else (pr-str (str x)))) '.a:expr.'))',
\ a:0 ? a:1 : foreplay#ns())
if body ==# ''
return ''
else
return eval(body)
endif
endfunction
" }}}1
" Eval {{{1
let foreplay#skip = 'synIDattr(synID(line("."),col("."),1),"name") =~? "comment\\|string\\|char"'
function! s:opfunc(type) abort
let sel_save = &selection
let cb_save = &clipboard
let reg_save = @@
try
set selection=inclusive clipboard-=unnamed clipboard-=unnamedplus
if a:type =~ '^\d\+$'
silent exe 'normal! ^v'.a:type.'$hy'
elseif a:type =~# '^.$'
silent exe "normal! `<" . a:type . "`>y"
elseif a:type ==# 'line'
silent exe "normal! '[V']y"
elseif a:type ==# 'block'
silent exe "normal! `[\<C-V>`]y"
elseif a:type ==# 'outer'
call searchpair('(','',')', 'Wbcr', g:foreplay#skip)
silent exe "normal! vaby"
else
silent exe "normal! `[v`]y"
endif
redraw
return @@
finally
let @@ = reg_save
let &selection = sel_save
let &clipboard = cb_save
endtry
endfunction
function! s:filterop(type) abort
let reg_save = @@
try
let expr = s:opfunc(a:type)
let @@ = matchstr(expr, '^\n\+').foreplay#eval(expr, foreplay#ns()).matchstr(expr, '\n\+$')
if @@ !~# '^\n*$'
normal! gvp
endif
catch /^Clojure:/
return ''
finally
let @@ = reg_save
endtry
endfunction
function! s:printop(type) abort
let s:todo = s:opfunc(a:type)
call feedkeys("\<Plug>ForeplayPrintLast")
endfunction
function! s:print_last() abort
try
echo foreplay#eval(s:todo)
catch /^Clojure:/
endtry
return ''
endfunction
function! s:editop(type) abort
call feedkeys(&cedit . "\<Home>", 'n')
let input = s:input(substitute(substitute(s:opfunc(a:type), "\s*;[^\n]*", '', 'g'), '\n\+\s*', ' ', 'g'))
try
if input !=# ''
echo foreplay#eval(input)
endif
catch /^Clojure:/
return ''
endtry
endfunction
function! s:Eval(bang, line1, line2, count, args) abort
if a:args !=# ''
let expr = a:args
else
if a:count ==# 0
normal! ^
let line1 = searchpair('(','',')', 'bcrn', g:foreplay#skip)
let line2 = searchpair('(','',')', 'rn', g:foreplay#skip)
else
let line1 = a:line1
let line2 = a:line2
endif
if !line1 || !line2
return ''
endif
let expr = join(getline(line1, line2), "\n")
if a:bang
exe line1.','.line2.'delete _'
endif
endif
try
let result = foreplay#eval(expr)
if a:bang
if a:args !=# ''
call append(a:line1, result)
exe a:line1
else
call append(a:line1-1, result)
exe a:line1-1
endif
else
echo result
endif
catch /^Clojure:/
endtry
return ''
endfunction
" If we call input() directly inside a try, and the user opens the command
" line window and tries to switch out of it (such as with ctrl-w), Vim will
" crash when the command line window closes. Adding an indirect function call
" works around this.
function! s:actually_input(...)
return call(function('input'), a:000)
endfunction
function! s:input(default) abort
if !exists('g:FOREPLAY_HISTORY')
let g:FOREPLAY_HISTORY = []
endif
try
let s:input = bufnr('%')
let s:oldhist = s:histswap(g:FOREPLAY_HISTORY)
return s:actually_input(foreplay#ns().'=> ', a:default, 'customlist,foreplay#eval_complete')
finally
unlet! s:input
if exists('s:oldhist')
let g:FOREPLAY_HISTORY = s:histswap(s:oldhist)
endif
endtry
endfunction
function! s:inputclose() abort
let l = substitute(getcmdline(), '"\%(\\.\|[^"]\)*"\|\\.', '', 'g')
let open = len(substitute(l, '[^(]', '', 'g'))
let close = len(substitute(l, '[^)]', '', 'g'))
if open - close == 1
return ")\<CR>"
else
return ")"
endif
endfunction
function! s:inputeval() abort
let input = s:input('')
redraw
if input ==# ''
return ''
else
try
echo foreplay#eval(input)
return ''
catch /^Clojure:/
return ''
catch
return 'echoerr '.string(v:exception)
endtry
endif
endfunction
function! s:recall() abort
try
cnoremap <expr> ) <SID>inputclose()
let input = s:input('(')
if input =~# '^(\=$'
return ''
else
return foreplay#eval(input)
endif
catch /^Clojure:/
return ''
finally
silent! cunmap )
endtry
endfunction
function! s:histswap(list)
let old = []
for i in range(1, histnr('@') * (histnr('@') > 0))
call extend(old, [histget('@', i)])
endfor
call histdel('@')
for entry in a:list
call histadd('@', entry)
endfor
return old
endfunction
nnoremap <silent> <Plug>ForeplayPrintLast :exe <SID>print_last()<CR>
nnoremap <silent> <Plug>ForeplayPrint :<C-U>set opfunc=<SID>printop<CR>g@
xnoremap <silent> <Plug>ForeplayPrint :<C-U>call <SID>printop(visualmode())<CR>
nnoremap <silent> <Plug>ForeplayFilter :<C-U>set opfunc=<SID>filterop<CR>g@
xnoremap <silent> <Plug>ForeplayFilter :<C-U>call <SID>filterop(visualmode())<CR>
nnoremap <silent> <Plug>ForeplayEdit :<C-U>set opfunc=<SID>editop<CR>g@
xnoremap <silent> <Plug>ForeplayEdit :<C-U>call <SID>editop(visualmode())<CR>
nnoremap <Plug>ForeplayPrompt :exe <SID>inputeval()<CR>
noremap! <Plug>ForeplayRecall <C-R>=<SID>recall()<CR>
function! s:setup_eval() abort
command! -buffer -bang -range=0 -nargs=? -complete=customlist,foreplay#eval_complete Eval :exe s:Eval(<bang>0, <line1>, <line2>, <count>, <q-args>)
nmap <buffer> cp <Plug>ForeplayPrint
nmap <buffer> cpp <Plug>ForeplayPrintab
nmap <buffer> c! <Plug>ForeplayFilter
nmap <buffer> c!! <Plug>ForeplayFilterab
nmap <buffer> cq <Plug>ForeplayEdit
nmap <buffer> cqq <Plug>ForeplayEditab
nmap <buffer> cqp <Plug>ForeplayPrompt
exe 'nmap <buffer> cqc <Plug>ForeplayPrompt' . &cedit . 'i'
map! <buffer> <C-R>( <Plug>ForeplayRecall
endfunction
function! s:cmdwinenter()
setlocal filetype=clojure
endfunction
function! s:cmdwinleave()
setlocal filetype< omnifunc<
endfunction
augroup foreplay_eval
autocmd!
autocmd FileType clojure call s:setup_eval()
autocmd CmdWinEnter @ if exists('s:input') | call s:cmdwinenter() | endif
autocmd CmdWinLeave @ if exists('s:input') | call s:cmdwinleave() | endif
augroup END
" }}}1
" :Require {{{1
function! s:Require(bang, ns)
let cmd = ('(require '.s:qsym(a:ns ==# '' ? foreplay#ns() : a:ns).' :reload'.(a:bang ? '-all' : '').')')
echo cmd
try
call foreplay#eval(cmd)
return ''
catch /^Clojure:.*/
return ''
endtry
endfunction
function! s:setup_require()
command! -buffer -bar -bang -complete=customlist,foreplay#ns_complete -nargs=? Require :exe s:Require(<bang>0, <q-args>)
nnoremap <silent><buffer> cpr :Require<CR>
nnoremap <silent><buffer> cpR :Require!<CR>
endfunction
augroup foreplay_require
autocmd!
autocmd FileType clojure call s:setup_require()
augroup END
" }}}1
" Go to source {{{1
function! foreplay#source(symbol) abort
let c = foreplay#local_client()
call c.require(foreplay#ns())
let cmd =
\ " (when-let [v (resolve " . s:qsym(a:symbol) .')]' .
\ ' (when-let [filepath (:file (meta v))]' .
\ ' (when-let [url (.getResource (clojure.lang.RT/baseLoader) filepath)]' .
\ ' (symbol (str (str "+" (:line (meta v))) " "' .
\ ' (if (= "jar" (.getProtocol url))' .
\ ' (str "zip" (.replaceFirst (.getFile url) "!/" "::"))' .
\ ' (.getFile url)))))))'
let result = get(split(c.eval(cmd, foreplay#ns()).value, "\n"), 0, '')
return result ==# 'nil' ? '' : result
endfunction
function! s:Edit(cmd, keyword) abort
if a:keyword =~# '^\k\+/$'
let location = foreplay#findfile(a:keyword[0: -2])
elseif a:keyword =~# '^\k\+\.[^/.]\+$'
let location = foreplay#findfile(a:keyword)
else
let location = foreplay#source(a:keyword)
endif
if location !=# ''
if matchstr(location, '^+\d\+ \zs.*') ==# expand('%:p') && a:cmd ==# 'edit'
return matchstr(location, '\d\+')
else
return a:cmd.' '.location.'|let &l:path = '.string(&l:path)
endif
endif
let v:errmsg = "Couldn't find source for ".a:keyword
return 'echoerr v:errmsg'
endfunction
augroup foreplay_source
autocmd!
autocmd FileType clojure setlocal includeexpr=tr(v:fname,'.-','/_')
autocmd FileType clojure setlocal suffixesadd=.clj,.java
autocmd FileType clojure setlocal define=^\\s*(def\\w*
autocmd FileType clojure command! -bar -buffer -nargs=1 -complete=customlist,foreplay#eval_complete Djump :exe s:Edit('edit', <q-args>)
autocmd FileType clojure command! -bar -buffer -nargs=1 -complete=customlist,foreplay#eval_complete Dsplit :exe s:Edit('split', <q-args>)
autocmd FileType clojure nnoremap <silent><buffer> [<C-D> :<C-U>exe <SID>Edit('edit', expand('<cword>'))<CR>
autocmd FileType clojure nnoremap <silent><buffer> ]<C-D> :<C-U>exe <SID>Edit('edit', expand('<cword>'))<CR>
autocmd FileType clojure nnoremap <silent><buffer> <C-W><C-D> :<C-U>exe <SID>Edit('split', expand('<cword>'))<CR>
autocmd FileType clojure nnoremap <silent><buffer> <C-W>d :<C-U>exe <SID>Edit('split', expand('<cword>'))<CR>
autocmd FileType clojure nnoremap <silent><buffer> <C-W>gd :<C-U>exe <SID>Edit('tabedit', expand('<cword>'))<CR>
augroup END
" }}}1
" Go to file {{{1
function! foreplay#findfile(path) abort
let c = foreplay#local_client()
call c.require(foreplay#ns())
let cmd =
\ '(symbol' .
\ ' (or' .
\ ' (when-let [url (.getResource (clojure.lang.RT/baseLoader) %s)]' .
\ ' (if (= "jar" (.getProtocol url))' .
\ ' (str "zip" (.replaceFirst (.getFile url) "!/" "::"))' .
\ ' (.getFile url)))' .
\ ' ""))'
let path = a:path
if path !~# '[/.]' && path =~# '^\k\+$'
let aliascmd = printf(cmd,
\ '(if-let [ns ((ns-aliases *ns*) '.s:qsym(path).')]' .
\ ' (str (.replace (.replace (str (ns-name ns)) "-" "_") "." "/") ".clj")' .
\ ' "'.path.'.clj")')
let result = get(split(c.eval(aliascmd, foreplay#ns()).value, "\n"), 0, '')
else
if path !~# '/'
let path = tr(path, '.-', '/_')
endif
if path !~# '\.\w\+$'
let path .= '.clj'
endif
let result = get(split(c.eval(printf(cmd, '"'.escape(path, '"').'"'), foreplay#ns()).value, "\n"), 0, '')
endif
if result ==# ''
return findfile(path, &l:path)
else
return result
endif
endfunction
function! s:GF(cmd, file) abort
if a:file =~# '^[^/]*/[^/.]*$' && a:file =~# '^\k\+$'
let [file, jump] = split(a:file, "/")
else
let file = a:file
endif
let file = foreplay#findfile(file)
if file ==# ''
let v:errmsg = "Couldn't find file for ".a:file
return 'echoerr v:errmsg'
endif
return a:cmd .
\ (exists('jump') ? ' +sil!\ djump\ ' . jump : '') .
\ ' ' . fnameescape(file) .
\ '| let &l:path = ' . string(&l:path)
endfunction
augroup foreplay_go_to_file
autocmd!
autocmd FileType clojure nnoremap <silent><buffer> gf :<C-U>exe <SID>GF('edit', expand('<cfile>'))<CR>
autocmd FileType clojure nnoremap <silent><buffer> <C-W>f :<C-U>exe <SID>GF('split', expand('<cfile>'))<CR>
autocmd FileType clojure nnoremap <silent><buffer> <C-W><C-F> :<C-U>exe <SID>GF('split', expand('<cfile>'))<CR>
autocmd FileType clojure nnoremap <silent><buffer> <C-W>gf :<C-U>exe <SID>GF('tabedit', expand('<cfile>'))<CR>
augroup END
" }}}1
" Documentation {{{1
function! s:buffer_path(...) abort
let buffer = a:0 ? a:1 : exists('s:input') ? s:input : '%'
if getbufvar(buffer, '&buftype') =~# '^no'
return ''
endif
let path = substitute(fnamemodify(bufname(buffer), ':p'), '\C^zipfile:\(.*\)::', '\1/', '')
for dir in classpath#split(classpath#from_vim(getbufvar(buffer, '&path')))
if dir !=# '' && path[0 : strlen(dir)-1] ==# dir
return path[strlen(dir)+1:-1]
endif
endfor
return ''
endfunction
function! s:tons(path) abort
return tr(substitute(a:path, '\.\w\+$', '', ''), '\/_', '..-')
endfunction
function! foreplay#ns() abort
let lnum = 1
while lnum < line('$') && getline(lnum) =~# '^\s*\%(;.*\)\=$'
let lnum += 1
endwhile
let ns = matchstr(getline(lnum), '\C^(\s*\%(in-ns\s*''\|ns\s\+\)\zs\k\+\ze')
if ns !=# ''
return ns
endif
let path = s:buffer_path()
return s:tons(path ==# '' ? 'user' : path)
endfunction
function! s:Lookup(ns, macro, arg) abort
" doc is in clojure.core in older Clojure versions
try
call foreplay#eval("(require '".a:ns.") (eval (list (if (ns-resolve 'clojure.core '".a:macro.") 'clojure.core/".a:macro." '".a:ns.'/'.a:macro.") '".a:arg.'))')
catch /^Clojure:/
catch /.*/
echohl ErrorMSG
echo v:exception
echohl None
endtry
return ''
endfunction
function! s:inputlist(label, entries)
let choices = [a:label]
for i in range(len(a:entries))
let choices += [printf('%2d. %s', i+1, a:entries[i])]
endfor
let choice = inputlist(choices)
if choice
return a:entries[choice-1]
else
return ''
endif
endfunction
function! s:Apropos(pattern) abort
if a:pattern =~# '^#\="'
let pattern = a:pattern
elseif a:pattern =~# '^^'
let pattern = '#"' . a:pattern . '"'
else
let pattern = '"' . a:pattern . '"'
endif
let matches = foreplay#evalparse('(apropos '.pattern.')')
if empty(matches)
return ''
endif
let choice = s:inputlist('Look up docs for:', matches)
if choice !=# ''
return 'echo "\n"|Doc '.choice
else
return ''
endif
endfunction
function! s:K()
let word = expand('<cword>')
let java_candidate = matchstr(word, '^\%(\w\+\.\)*\u\l\w*\ze\%(\.\|\/\w\+\)\=$')
if java_candidate !=# ''
return 'Javadoc '.java_candidate
else
return 'Doc '.word
endif
endfunction
augroup foreplay_doc
autocmd!
autocmd FileType clojure nnoremap <buffer> K :<C-R>=<SID>K()<CR><CR>
autocmd FileType clojure nnoremap <buffer> [d :Source <C-R><C-W><CR>
autocmd FileType clojure nnoremap <buffer> ]d :Source <C-R><C-W><CR>
autocmd FileType clojure command! -buffer -nargs=1 Apropos :exe s:Apropos(<q-args>)
autocmd FileType clojure command! -buffer -nargs=1 FindDoc :exe s:Lookup('clojure.repl', 'find-doc', printf('#"%s"', <q-args>))
autocmd FileType clojure command! -buffer -bar -nargs=1 Javadoc :exe s:Lookup('clojure.java.javadoc', 'javadoc', <q-args>)
autocmd FileType clojure command! -buffer -bar -nargs=1 -complete=customlist,foreplay#eval_complete Doc :exe s:Lookup('clojure.repl', 'doc', <q-args>)
autocmd FileType clojure command! -buffer -bar -nargs=1 -complete=customlist,foreplay#eval_complete Source :exe s:Lookup('clojure.repl', 'source', <q-args>)
augroup END
" }}}1
" Leiningen {{{1
function! s:hunt(start, anchor) abort
let root = simplify(fnamemodify(a:start, ':p:s?[\/]$??'))
if !isdirectory(fnamemodify(root, ':h'))
return ''
endif
let previous = ""
while root !=# previous
if filereadable(root . '/' . a:anchor) && isdirectory(root . '/src')
return root
endif
let previous = root
let root = fnamemodify(root, ':h')
endwhile
return ''
endfunction
if !exists('s:leiningen_repl_ports')
let s:leiningen_repl_ports = {}
endif
function! s:leiningen_connect()
if !exists('b:leiningen_root')
return
endif
let portfile = b:leiningen_root . '/target/repl-port'
if getfsize(portfile) > 0 && getftime(portfile) !=# get(s:leiningen_repl_ports, b:leiningen_root, -1)
let port = readfile(portfile, 'b', 1)[0]
let s:leiningen_repl_ports[b:leiningen_root] = getftime(portfile)
try
call s:register_connection(nrepl#foreplay_connection#open(port), b:leiningen_root)
catch /^nREPL: Connection/
call delete(portfile)
endtry
endif
endfunction
function! s:leiningen_init() abort
if !exists('b:leiningen_root')
let root = s:hunt(expand('%:p'), 'project.clj')
if root !=# ''
let b:leiningen_root = root
endif
endif
if !exists('b:leiningen_root')
return
endif
let b:java_root = b:leiningen_root
setlocal makeprg=lein efm=%+G
call s:leiningen_connect()
endfunction
augroup foreplay_leiningen
autocmd!
autocmd User ForeplayPreConnect call s:leiningen_connect()
autocmd FileType clojure call s:leiningen_init()
augroup END
" }}}1
" vim:set et sw=2:

132
python/nrepl_fireplace.py Normal file
View File

@ -0,0 +1,132 @@
import os
import re
import select
import socket
import sys
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
def noop():
pass
def vim_encode(data):
if isinstance(data, list):
return "[" + ",".join([vim_encode(x) for x in data]) + "]"
elif isinstance(data, dict):
return "{" + ",".join([vim_encode(x)+":"+vim_encode(y) for x,y in data.items()]) + "}"
elif isinstance(data, str):
str_list = []
for c in data:
if (0 <= ord(c) and ord(c) <= 31) or c == '"' or c == "\\":
str_list.append("\\%03o" % ord(c))
else:
str_list.append(c)
return '"' + ''.join(str_list) + '"'
elif isinstance(data, int):
return str(data)
else:
raise TypeError("can't encode a " + type(data).__name__)
def bdecode(f, char=None):
if char == None:
char = f.read(1)
if char == 'l':
l = []
while True:
char = f.read(1)
if char == 'e':
return l
l.append(bdecode(f, char))
elif char == 'd':
d = {}
while True:
char = f.read(1)
if char == 'e':
return d
key = bdecode(f, char)
d[key] = bdecode(f)
elif char == 'i':
i = ''
while True:
char = f.read(1)
if char == 'e':
return int(i)
i += char
elif char.isdigit():
i = int(char)
while True:
char = f.read(1)
if char == ':':
return f.read(i)
i = 10 * i + int(char)
elif char == '':
raise EOFError("unexpected end of bencode data")
else:
raise TypeError("unexpected type "+char+"in bencode data")
class Connection:
def __init__(self, host, port, custom_poll=noop, keepalive_file=None):
self.custom_poll = custom_poll
self.keepalive_file = keepalive_file
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(8)
s.connect((host, int(port)))
s.setblocking(1)
self.socket = s
def poll(self):
self.custom_poll()
if self.keepalive_file and not os.path.exists(self.keepalive_file):
exit(0)
def close(self):
return self.socket.close()
def send(self, payload):
if sys.version_info[0] >= 3:
self.socket.sendall(bytes(payload, 'UTF-8'))
else:
self.socket.sendall(payload)
return ''
def receive(self, char=None):
f = self.socket.makefile()
while len(select.select([f], [], [], 0.1)[0]) == 0:
self.poll()
try:
return bdecode(f)
finally:
f.close()
def call(self, payload, terminators, selectors):
self.send(payload)
responses = []
while True:
response = self.receive()
for key in selectors:
if response[key] != selectors[key]:
continue
responses.append(response)
if 'status' in response and set(terminators) & set(response['status']):
return responses
def dispatch(host, port, poll, keepalive, command, *args):
conn = Connection(host, port, poll, keepalive)
try:
return getattr(conn, command)(*args)
finally:
conn.close()
def main(host, port, keepalive, command, *args):
try:
sys.stdout.write(vim_encode(dispatch(host, port, noop, keepalive, command, *[bdecode(StringIO(arg)) for arg in args])))
except Exception:
print((sys.exc_info()[1]))
exit(1)
if __name__ == "__main__":
main(*sys.argv[1:])