Skip to content

Commit

Permalink
initial commit, v0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
kbairak committed Mar 15, 2015
0 parents commit 3d81f06
Show file tree
Hide file tree
Showing 4 changed files with 295 additions and 0 deletions.
71 changes: 71 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Column Tags - Follow your tags in column-view

## Overview

This plugin aims to help you navigate through you code using
[tags](http://ctags.sourceforge.net/). Vim already has good support for this.
Having generated a tags file in your current working directory, if you move
your cursor over a keyword while in command mode and press `CTRL-]`, you will
navigate to the definition of the keyword within your project and pressing
`CTRL-t` will take you back to where you came from.

Using this plugin, the experience is very similar, but you can take advantage
of Vim's support for multiple windows and a wide screen to maintain an overview
of both the part of the code you navigated from and the part of the code that
hosts the definition of you keyword. The final experience is reminiscent of the
column-view of Mac's file manager program, Finder.

![Column-view screenshot](http://cdn.osxdaily.com/wp-content/uploads/2010/02/mac-os-x-finder-column-view.JPG)

To get started, you must create a tags file in the base folder of you project.
Most developmnent environments come with *ctags* installed, so simply run:

cd <path-to-project>
ctags -R .

While using the plugin, you will have up to 3 windows displayed as columns.

With `CTRL-]`, you can follow the tag under the cursor in a new vertical split.
If the number of existing columns is `g:max_columns` and the rightmost column
is focused, the view will be shifted to the left before doing the vertical
split. If you follow a tag from a column that is not rightmost, the new column
will replace those that are to the right of the one that was in focus. The goal
is to be able to view both the part of the code that executes a function or
class and its definition at the same time.

With `CTRL-t`, you can go back to where you were before following a tag. If the
column under focus is not the leftmost, this simply means focusing on the
column to the left. If the leftmost column was focused, the windows that got
hidden by following tags and moving towards the right will start being
revealed.


## Installation

Just paste the package's contents into into your .vim directory.


## Installing with [Pathogen](https://github.com/tpope/vim-pathogen)

1. `cd ~/.vim/bundle`
2. `git clone git://github.com/kbairak/ColumnTags.vim.git


## Usage

- Press `CTRL-]` to follow a tag and open it in a column right of the one you
are focused on
- Press `CTRL-t` to go back to where you came from before following a tag. If
you are not on the leftmost column, this will simpley focus the column to the
left. If you are on the leftmost column, this wil shift all columns to the
right and reveal the file you navigated to the leftmost column from
- Press `CTRL-,` to shift all columns to the right and reveal the file you
navigated to the leftmost column from


## Customization

You can customize the maximum number of columns visible by putting this in your
.vimrc (default is 3):

let g:max_columns = 4
43 changes: 43 additions & 0 deletions doc/columntags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
*ColumnTags* Plugin for following tags in column-view

This plugin offers commands and mappings to better navigate tags revealing both
the calling code and the definitions.

Commands:

:CollumnTagOpen *:CollumnTagOpen*
CTRL_] Follow the tag under the cursor in a new vertical
split. If the number of existing columns is
g:max_columns and the rightmost column is focused,
the view will be shifted to the left before doing
the vertical split. If you follow a tag from a
column that is not rightmost, the new column will
replace those that are to the right of the one that
was in focus.

:CollumnTagClose *:CollumnTagClose*
CTRL_t Go back to where you were before following a tag.
If the column under focus is not the leftmost, this
means simply focusing on the column to the left. If
the leftmost column was focused, the windows that
got hidden by following tags and moving towards the
right will start being revealed.

:CollumnTagShiftLeft *:CollumnTagShiftLeft*
CTRL_, Shift all you columns to the left, revealing
columns that got hidden as your were navigating
tags to ther right, without changing the focused
window.


*ColumnTags-settings*
You can override the above mappings in your .vimrc, like this:

nmap <silent> <C-.> :CollumnTagOpen<CR>
nmap <silent> <C-,> :CollumnTagClose<CR>
nmap <silent> <C-t> :CollumnTagShiftLeft<CR>

You can override the maximum number of columns in your .vimrc like this
(default is 3):

let g:max_columns = 4
5 changes: 5 additions & 0 deletions doc/tags
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
:CollumnTagClose columntags.txt /*:CollumnTagClose*
:CollumnTagOpen columntags.txt /*:CollumnTagOpen*
:CollumnTagShiftLeft columntags.txt /*:CollumnTagShiftLeft*
ColumnTags columntags.txt /*ColumnTags*
ColumnTags-settings columntags.txt /*ColumnTags-settings*
176 changes: 176 additions & 0 deletions plugin/columntags.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
" Vim global plugin to navigate through tags like mac finder's column view
" Last Change: 2015 Mar 14
" Maintainer: Konstantinos Bairaktaris <[email protected]>
" License: This file is placed in the public domain
" Version: 0.1

if exists("g:loaded_columntags")
finish
endif
let g:loaded_columntags = 1

" Globals
let g:max_columns = 3

" Stash
" camelCase for staticmethods, underscore for instance methods
let s:Stash = {}
function s:Stash.New()
let l:new_stash = copy(self)
let l:new_stash['_stash'] = []
return l:new_stash
endfunction

function s:Stash.getForTab()
if ! exists('t:stash')
let t:stash = s:Stash.New()
endif
return t:stash
endfunction

function s:Stash.push(value)
call add(self['_stash'], a:value)
endfunction

function s:Stash.pop()
let l:tail = len(self['_stash']) - 1
let l:return_value = self['_stash'][l:tail]
call remove(self['_stash'], l:tail)
return l:return_value
endfunction

function s:Stash.is_empty()
return len(self['_stash']) == 0
endfunction

" Utils
function s:get_window_count()
return winnr('$')
endfunction

function s:get_focused_window()
return winnr()
endfunction

function s:is_rightmost()
return s:get_focused_window() == s:get_window_count()
endfunction

function s:is_leftmost()
return s:get_focused_window() == 1
endfunction

function s:split_right()
vsplit
wincmd l
execute 'tjump ' . expand('<cword>')
silent! foldopen!
endfunction

function s:focus_window(target)
let l:source = s:get_focused_window()
if l:source < a:target
execute (a:target - l:source) . 'wincmd l'
elseif a:target < l:source
execute (l:source - a:target) . 'wincmd h'
endif
endfunction

function s:delete_window(target)
let l:source = s:get_focused_window()
call s:focus_window(a:target)
quit
if l:source < a:target
call s:focus_window(l:source)
elseif a:target < l:source
call s:focus_window(l:source - 1)
endif
endfunction

function s:delete_righter()
let l:source = s:get_focused_window()
while s:get_focused_window() < s:get_window_count()
call s:delete_window(l:source + 1)
endwhile
endfunction

" Main functions
function s:column_tag_open()
if ! s:is_rightmost()
call s:delete_righter()
endif

let l:stash = s:Stash.getForTab()
if s:get_window_count() >= g:max_columns
call s:focus_window(1)
call l:stash.push({'file': expand('%'), 'line': line('.')})
call s:delete_window(1)
call s:focus_window(g:max_columns - 1)
endif
call s:split_right()

while ! l:stash.is_empty() && s:get_window_count() < g:max_columns
call s:column_tag_shift_left()
endwhile
endfunction

function s:column_tag_back()
if ! s:is_leftmost()
wincmd h
return
endif

let l:stash = s:Stash.getForTab()
if l:stash.is_empty()
return
endif

let l:window_count = s:get_window_count()
if l:window_count >= g:max_columns
call s:delete_window(l:window_count)
call s:focus_window(1)
endif

vsplit
let l:value = l:stash.pop()
let l:filepath = l:value['file']
let l:linenumber = l:value['line']
execute 'edit ' . l:filepath
execute 'goto ' . line2byte(l:linenumber)
foldopen!
endfunction

function s:column_tag_shift_left()
let l:stash = s:Stash.getForTab()
if l:stash.is_empty()
return
endif

let l:source = s:get_focused_window()
if s:get_window_count() == g:max_columns
call s:delete_window(g:max_columns)
endif

call s:focus_window(1)
call s:column_tag_back()

if l:source == g:max_columns
let l:source -= 1
endif
call s:focus_window(l:source + 1)
endfunction

" Mappings
command CollumnTagOpen call s:column_tag_open()
command CollumnTagBack call s:column_tag_back()
command CollumnTagShiftLeft call s:column_tag_shift_left()

if ! hasmapto('CollumnTagOpen')
nmap <silent> <C-]> :CollumnTagOpen<CR>
endif
if ! hasmapto('CollumnTagBack')
nmap <silent> <C-t> :CollumnTagBack<CR>
endif
if ! hasmapto('CollumnTagShiftLeft')
nmap <silent> <C-,> :CollumnTagShiftLeft<CR>
endif

0 comments on commit 3d81f06

Please sign in to comment.