Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Referring to evaluation ranges in :IcedEval #407

Open
sheluchin opened this issue May 16, 2022 · 13 comments
Open

Referring to evaluation ranges in :IcedEval #407

sheluchin opened this issue May 16, 2022 · 13 comments
Assignees
Labels
enhancement New feature or request neovim Neovim's behaviors waiting

Comments

@sheluchin
Copy link

sheluchin commented May 16, 2022

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!

@liquidz
Copy link
Owner

liquidz commented May 16, 2022

@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.

function! iced#operation#eval_and_tap(type) abort
return s:eval({code -> iced#repl#execute('eval_code', printf('(clojure.core/tap> %s)', code))})
endfunction

@liquidz liquidz added the enhancement New feature or request label May 16, 2022
@sheluchin
Copy link
Author

@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?

@sheluchin
Copy link
Author

sheluchin commented May 25, 2022

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.

@liquidz
Copy link
Owner

liquidz commented May 25, 2022

@sheluchin Nice work! Thanks!
I'll have a look.

@liquidz
Copy link
Owner

liquidz commented May 26, 2022

@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.

@sheluchin
Copy link
Author

sheluchin commented May 26, 2022

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.

@liquidz
Copy link
Owner

liquidz commented May 26, 2022

@sheluchin Oh, it seems a problem in neovim. (works in vim)
I'll fix.

@liquidz
Copy link
Owner

liquidz commented May 26, 2022

Ah, neovim has not been applied patch 8.2.3619 yet.
vim/vim@777175b
Hmm, we cannot realize with this method in neovim..

I'll reconsider.

@sheluchin
Copy link
Author

@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.

@liquidz
Copy link
Owner

liquidz commented May 30, 2022

@sheluchin Thanks!
I agree with you.
I'll check neovim repository occasionally.

@liquidz liquidz added neovim Neovim's behaviors waiting labels Jun 20, 2022
@sheluchin
Copy link
Author

neovim/neovim#19846 🎉

@liquidz
Copy link
Owner

liquidz commented Aug 25, 2022

Nice catch!

@liquidz liquidz self-assigned this Aug 25, 2022
@sheluchin
Copy link
Author

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 🤷‍♂️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request neovim Neovim's behaviors waiting
Projects
None yet
Development

No branches or pull requests

2 participants