Run J script as if it were line-by-line entered into the interpreter

Viewed 152

Is there a way to run the script as if it were typed into the interpeter? The benefits are that I don't need echos everywhere, the work done is saved as a file, and I can use vim to do the editing. Example:

example.ijs

x =. 1
x + 3

terminal

   x =. 1
   x + 3
4

If not, I'll write a vimscript that can do the above then share them here. The advantage of a vimscript solution is that I could have commands to run the entire file, the current line, the current selection, everything up to and including the current line, or whatever else is useful.

Related but not a duplicate: How to call J (ijconsole) with a script automatically

4 Answers

It sounds like you are asking for this to be solved for the jconsole interface. I don't have answer for that, but would point out that that functionality is available for both the JHS and jQt interfaces. If you don't mind switching to a different interface then that would be a quick and easy solution.

The easiest way to interactively run a script is to use labs command:

 load'labs/lab'

 lab'myscript.ijt'    
 1 of 2 in myscript.ijt
 x =. 1

 NB. press Ctrl+'.' to advance.
 x + 3
4

 NB. Run the whole script.
 lab 1 _
 x =. 1
 x + 3
4

More info about labs here

If you want to non-interactively run a script as if typed in the console, you can just feed the script to j (in linux):

j < myscript.ijs
4

Alternatively, to

see the lines on the screen just as though they had been typed from the keyboard

from a script, you can use 0!:1:

 0!:1 < 'myscript.ijs'
 x =. 1
 x + 3
4

This is the vimscript solution I mentioned. It's as far as I can tell language agnostic as well.

" Global variable dictates whether new terminals are opened
" horizontally ('h') or vertically ('v').
let g:terminalsplit = 'h'

" Add execution strings for each language you use.
augroup terminalcommands
    autocmd!
    autocmd Filetype j      let g:cmdstr = 'jconsole.cmd'
    autocmd Filetype python let g:cmdstr = 'python'
augroup END

" Close all terminals
nnoremap <silent> <leader>p :call CloseTerminal()<cr>
" Run file
nnoremap <leader>h :call Run(g:cmdstr, 'script')<cr>
" Run as if file were entered line-by-line into the interpreter
" Mappings for: Line, selection, file up to line, entire file
nnoremap <leader>j yy:call Run(g:cmdstr, 'interpreter')<cr>
vnoremap <leader>j ygv<esc>:call Run(g:cmdstr, 'interpreter')<cr>
nnoremap <leader>k Vggy<c-O>:call Run(g:cmdstr, 'interpreter')<cr>
nnoremap <leader>l mzggVGy'z:call Run(g:cmdstr, 'interpreter')<cr>

function! Run(cmdstr, mode)
    let filepath = expand('%:p') " Copy filepath before switch to terminal
    call CloseTerminal()
    call OpenTerminal()
    echo g:clear . " & " . a:cmdstr
    call feedkeys(g:clear . " & " . a:cmdstr) " Begin run command
    call RunCode(filepath, a:mode)
    call feedkeys("\<c-w>p") " Switch back to file window
endfunction

function! CloseTerminal()
    if has('nvim')
        let terminals = split(execute('filter/term:/ls'), '\n')
    else
        let terminals = split(execute('filter/!/ls'), '\n')
    endif
    for i in range(len(terminals))
        silent! exe "bd! " . split(terminals[i], '  ')[0]
    endfor
endfunction

function! OpenTerminal()
    if g:terminalsplit == 'h'
        terminal
    elseif g:terminalsplit == 'v'
        vertical terminal
    else
        echo 'g:terminalsplit=' . &g:terminalsplit . '. Must be "h" or "v".'
    endif
endfunction

function! RunCode(filepath, mode)
    if a:mode == 'script'
        call feedkeys(" " . a:filepath . "\<cr>")
    elseif a:mode == 'interpreter'
        call feedkeys("\<cr>")
        call feedkeys("\<c-w>\"\"")
    else
        echo 'a:mode=' . a:mode . '. Must be "script" or "interpreter".'
    endif
endfunction

" Use to clear the terminal window before running the script
if has('unix')
    let g:clear = 'clear'
else
    let g:clear = 'cls'
endif

Use loadd rather than load to run the script and display the lines and results.

   loadd 'example.ijs'
   x =. 1
   x + 3
4
Related