mhinz / vim-startify

:link: The fancy start screen for Vim.
MIT License
5.3k stars 186 forks source link

Some help loading one .viminfo per session? #388

Closed eduardoarandah closed 5 years ago

eduardoarandah commented 5 years ago

Hello!

In vim I find very strange having global uppercase markers instead of markers per session.

example: In each project I create an "L" marker for a log.txt file, an "I" for an info.txt marker and so on.

I found that I can create a viminfo file with wviminfo! and read it again with rviminfo!

So I'm trying to use your SLoad function wrapping it into a PLoad (Project Load) command.

A Project Load would load a session AND viminfo file, making vim awesome!

But I'm new to vimscript and have no idea what I'm doing.

Can you point me in the right direction? Or consider having "Project Saving/Loading" into startify?

My Progress:

fun! PLoad(project_name)
  execute "rviminfo! ".fnameescape($HOME."/vimfiles/sessions/".a:project_name.".viminfo")
  execute "SLoad ".project_name
endfun

command! -nargs=? -bar -bang -complete=customlist,startify#session_list OpenProject call PLoad(<bang>0)
mhinz commented 5 years ago

Or consider having "Project Saving/Loading" into startify?

That won't happen, since I always just wanted a very thin wrapper around standard Vim sessions so that they're all in the same place for the sake of easily listing them in the Startify buffer.

And to be honest, I never heard anyone having such a workflow, but that doesn't necessarily mean anything!

Are the file names (info.txt, log.txt) the same for every project? In that case it would be easier to just create a small function, that searches these in the current project, and bind it to commands like :I and :L.

But that might just have been examples, so I'll happily help with all questions VimL!

I haven't really tested it, but this seems to do what you want:

function! s:pload(project_name) abort
  execute 'SLoad' a:project_name
  execute 'rviminfo!' fnameescape('/tmp/sessions/'.a:project_name.'.viminfo')
endfunction

function! s:psave(project_name) abort
  execute 'wviminfo!' fnameescape('/tmp/sessions/'.a:project_name.'.viminfo')
  execute 'SSave' a:project_name
endfunction

command! -nargs=1 -bar -complete=customlist,startify#session_list PLoad call s:pload(<f-args>)
command! -nargs=1 -bar -complete=customlist,startify#session_list PSave call s:psave(<f-args>)
eduardoarandah commented 5 years ago

Thanks!

I'll try it

It's just that vim doesn't work multi-folder, and for each project there's always files that don't belong to the code, in a very different path.

let's say that my website is in /www/petstore/public

and my info.txt lives in /home/me/projects/petstore/info.txt along with design files, and things that matter in that project with that client

if this is not "the vim way" to open files in two folders, then... how to do it?

mhinz commented 5 years ago

Yup, Vim has no idea what a "project" is and even the session feature is just a faltering solution for doing what you want. I guess Bram thought of these things too much being IDE features and didn't want them in his editor.

Anyway, if the approach from above (saving/restoring sessions + viminfo) doesn't work for you for some reason, I'd resort to per-project configuration files. Imagine every time you open a file, Vim searches the path from the current folder upwards for a file called .project.json. In your case it would look like:

{
  "info": "info.txt",
  "log": "log.txt"
}
function! s:project(key) abort
  let projectfile = findfile('.project.json', ';')
  if empty(projectfile)
    echo 'No .project.json found'
    return
  endif
  let data = json_decode(join(readfile(projectfile)))
  if has_key(data, a:key)
    execute 'edit' data[a:key]
  else
    echo 'No such key in '. projectfile
  endif
endfunction

command! -nargs=0 -bar Info call s:project('info')
command! -nargs=0 -bar Log  call s:project('log')

Then :Info would simply open whatever the nearest .project.json's info key points to.

eduardoarandah commented 5 years ago

That's awesome!

This is my progress:

To save your project (session & viminfo) call PSave myproject To load your project, simply call SLoad myproject (or the native :source command in vim)

The viminfo will be automatically loaded

function! s:psave(project_name) abort 
  let viminfodir = $HOME.'/vimfiles/sessions/'
  execute 'wviminfo!' fnameescape(viminfodir . a:project_name . '.viminfo')
  execute 'SSave' a:project_name
endfunction

" Command to save session & vim info
command! -nargs=1 -bar -complete=customlist,startify#session_list PSave call s:psave(<f-args>)

" Auto-restore viminfo when loading a session
" Restores: markers, registers, last-search and so on
autocmd SessionLoadPost * execute 'rviminfo! ' fnameescape(v:this_session.'.viminfo')

Flaws:

mhinz commented 5 years ago

viminfo doesn't autosaves, (maybe copying/extending startify code?)

When do you want it to save? You probably found it by now, but there are a lot of events available: :h {event}. Or wouldn't it be good enough to have a wrapper around :SLoad which also does :vwiminfo! before loading the session? Afterwards the SessionLoadPost autocmd would kick in and load the correct info file.

For checking path existence use either filereadable() or isdirectory().

I just pushed a commit that makes the function that Startify uses to get the session path public. But it doesn't check for existence on purpose, I try to avoid as much disk access as possible for performance reasons.

(Following code is untested, but you get the gist!)

let g:viminfo_dir = startify#get_session_path() .'_info'
if !isdirectory(g:viminfo_dir)
  call mkdir(g:viminfo_dir, 'p', 0700)
endif

function! s:get_viminfo_for_current_session() abort
  return g:viminfo_dir .'/'. fnamemodify(v:this_session, ':t') .'.viminfo'
endfunction

function! s:load_viminfo(command) abort
  let viminfo = s:get_viminfo_for_current_session()
  if filereadable(viminfo)
    execute a:command fnameescape(viminfo)
  endif
endfunction

function! s:psave(project_name) abort 
  execute 'wviminfo!' s:get_viminfo_for_current_session()
  execute 'SSave' a:project_name
endfunction

command! -nargs=1 -bar -complete=customlist,startify#session_list PSave call s:psave(<f-args>)

autocmd SessionLoadPost * call s:load_viminfo()
mhinz commented 5 years ago

(I'm closing this, since there's nothing concrete to fix, but please feel free to ask further questions.)

synthetic65535 commented 3 years ago

Here is my simple approach to manage viminfo and sessions together. Just 3 lines in .vimrc:

let SessionName = "default"
autocmd VimLeave,BufWrite * exec "mks! ~/.vim/sessions/".SessionName.".vim" | wviminfo
autocmd VimEnter * let &viminfo = "'1000,f1,<1000,n~/.vim/sessions/".SessionName.".viminfo" | rviminfo

How to use it. First you have to mkdir ~/.vim/sessions/ To create new session:

To restore session+viminfo:

You may also want to configure "sessionoptions". Hope someone may find it useful as first approach, while looking for a plugin dedicated for sessions management.