Open sheluchin opened 2 years ago
@sheluchin Currently there is no way to do that. But it is interesting idea! It would be great if we could generalize iced_eval_and_tap. cf. https://github.com/liquidz/vim-iced/blob/0382d4ca34e5993b121f882e68b951c16a8fbc99/autoload/iced/operation.vim#L59-L61
@liquidz Thank you for your consideration.
A generalized iced_eval_and_tap
sounds like a good approach.
Reveal has a similar feature which it implements by using *v
to mean the "currently selected value" in the given expression. For example, (prn *v)
would print the currently selected value in the Reveal window.
Maybe vim-iced could implement it similarly by using something like *v
or just %s
in the expression passed to :IcedEval
? Something like :IcedEval '(time %s)'
?
My knowledge of vimscript is unfortunately not very strong, but I hacked around the iced_eval_and_tap
function and think that I could figure out a rough implementation at some point. Do you happen to have another example in the codebase similar to using both selected_value
and input_code
rather than just the code
?
So I tried this:
function! iced#operation#eval_and_tap_wrapped(type, wrapper) abort
return s:eval({code -> iced#repl#execute(
\ 'eval_code',
\ printf('(clojure.core/tap> %s)', substitute(a:wrapper, '*v', code, 'g')))})
endfunction
And then with the cursor positioned at |
:
(iden|tity (do (Thread/sleep 5000) (str 123)))
I used :call iced#operation#eval_and_tap_wrapped("x", "(time *v)")
, which gave me this in my Reveal window:
"Elapsed time: 5001.441812 msecs"
; I think this line is a Reveal artifact you can probably ignore
(clojure.core/tap> (time (identity (do (Thread/sleep 5000) (str 123)))))
=> true
tap> "123"
I think that looks pretty good, but I'm sure it could be improved. What do you think, @liquidz?
I like this idea because it allows for a tighter integration between the editor and the interactive environment. For example, it would make it easy to create an editor mapping that would pass a datalog query directly to your query function without having to manually wrap the query in your code.
@sheluchin Nice work! Thanks! I'll have a look.
@sheluchin How about to define a function like below?
function! s:eval_wrapped(wrapper, type) abort
return s:eval({code -> iced#repl#execute('eval_code',
\ substitute(a:wrapper, '*v', code, 'g')
\ )})
endfunction
function! iced#operation#setup_wrapper(wrapper) abort
let &operatorfunc = funcref('s:eval_wrapped', [a:wrapper])
let s:register = v:register
endfunction
Then, we can define the following mappings.
nnoremap <silent> <Plug>(iced_eval_and_time) <Cmd>call iced#operation#setup_wrapper('(clojure.core/time *v)')<CR>g@
aug Fixme
au!
au FileType clojure nmap <buffer> <Leader>eat <Plug>(iced_eval_and_time)<Plug>(sexp_outer_list)``
aug END
It may be a little difficult to define, but this feature will allow us to freely define operations wchich wraps some code.
So by separating the evaluation and wrapper setup into two functions it makes it possible to use the setup generically to define bindings. Looks like a good idea.
It looks like there is a bug in your snippet because when I try to use it:
Error detected while processing function iced#operation#setup_wrapper:
line 1:
E703: Using a Funcref as a Number
E729: using Funcref as a String
I don't know vim script, but it looks like an operatorfunc
cannot receive an argument. I think it requires a different workaround. I can try find a solution sometime soon.
I'll note that this direction is slightly different from the initial idea of issue - using the evaluation range in :IcedEval
- but it does achieve exactly what I was looking for anyway.
@sheluchin Oh, it seems a problem in neovim. (works in vim) I'll fix.
Ah, neovim has not been applied patch 8.2.3619 yet. https://github.com/vim/vim/commit/777175b0df8c5ec3cd30d19a2e887e661ac209c8 Hmm, we cannot realize with this method in neovim..
I'll reconsider.
@liquidz thanks for giving this some thought. I think it's reasonable to wait for the patch to merged to Neovim if there's no easy workaround now. I can try just using my above snippet with :call iced#operation#eval_and_tap_wrapped("x", "(time *v)")
for the time being.
@sheluchin Thanks! I agree with you. I'll check neovim repository occasionally.
Nice catch!
One more idea about this... if it can also be possible to include the cursor position as an argument to the receiving Clojure function, it would make a powerful way to extend vim-iced functionality using Clojure code.
For example, given a form like:
(let [k :foo]
(x k)
(y |k)
(z k))
if the sending the outer top list can look like (my-fn *v 3)
, where *v
is the whole thing and 3
is the cursor position (let
= 0, [...]
= 1, (x k)
= 2, (y k)
= 3), it would make it possible to use Clojure to completely re-write the evaluation logic before evaluating. You could write Clojure code to only eval the y
call and ignore its siblings or re-arrange in any other way.
Just an idea :man_shrugging:
Not an issue, but a question.
Is it possible to refer to some evaluation range within the code passed to
:IcedEval
? For example, if I want to do something like:IcedEval '(time <outer list>)'
, is there some way to write that without literally copying the outer list?Thank you for the amazing plugin!