Class: Appear::Editor::Nvim

Inherits:
Service show all
Defined in:
lib/appear/editor/nvim.rb

Overview

Wraps nvim-remote to implement basic nvim support. I put this in my zshrc: ‘export NVIM_LISTEN_ADDRESS=“$HOME/.vim/sockets/vim-zsh-$$.sock”` this opens a separate nvim socket for each new Zsh shell. You’ll still get nvims trying to open the same socket if you use ctrl-z and fg and stuff to manage ‘em, but overall this solves needing command a bunch of different things.

Defined Under Namespace

Classes: Pane

Constant Summary collapse

NVR =

the ‘neovim-remote` command name

'nvr'.freeze
NEOVIM =

the ‘nvim` command name

'nvim'.freeze
NO_NAME =

the value to use for Vim buffers with no name. This is the UI value that Vim usually shows.

"[No Name]".freeze
BUFFER_FILENAME_EXPANSIONS =

This constant maps logical name to a string of filename-modifiers, for the vim fnamemodify() function. When we collect information about buffers, we get each of these expansions applied to the buffer name.

This mapping was copied from the BufExplorer vim plugin.

{
  :name => '',
  :absolute_path => ':p',
  :dirname => ':p:h',
  :relative_path => ':~:.',
  :relative_dirname => ':~:.:h',
  :shortname => ':t'
}.freeze
BUFFER_FILENAME_ORDER =

order in which we pass these to vim.

BUFFER_FILENAME_EXPANSIONS.keys.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BaseService

delegate, require_service, required_services

Constructor Details

#initialize(socket, svc = {}) ⇒ Nvim

Returns a new instance of Nvim.

Parameters:

  • socket (#to_s)

    UNIX socket to use to talk to Nvim.



90
91
92
93
94
# File 'lib/appear/editor/nvim.rb', line 90

def initialize(socket, svc = {})
  super(svc)
  @socket = socket
  @expr_memo = ::Appear::Util::Memoizer.new
end

Instance Attribute Details

#socket#to_s (readonly)

Returns path to the unix socket used to talk to Nvim.

Returns:

  • (#to_s)

    path to the unix socket used to talk to Nvim



73
74
75
# File 'lib/appear/editor/nvim.rb', line 73

def socket
  @socket
end

Class Method Details

.edit_command(filename) ⇒ Object

Spawn a new NVIM instance, then connect to its socket.



85
86
87
# File 'lib/appear/editor/nvim.rb', line 85

def self.edit_command(filename)
  ::Appear::Util::CommandBuilder.new(NEOVIM).args(filename)
end

.socketsArray<Pathname>

List all the sockets found in ~/.vim/sockets. I put this in my zshrc to make this work: ‘export NVIM_LISTEN_ADDRESS=“$HOME/.vim/sockets/vim-zsh-$$.sock”`

Returns:

  • (Array<Pathname>)


80
81
82
# File 'lib/appear/editor/nvim.rb', line 80

def self.sockets
  Dir.glob(File.expand_path('~/.vim/sockets/*.sock'))
end

Instance Method Details

#cmd(vimstring) ⇒ Object

Perform a Vim command

Parameters:

  • vimstring (String)

    the command, eg “:buffers”



109
110
111
# File 'lib/appear/editor/nvim.rb', line 109

def cmd(vimstring)
  run(command.flag('c', vimstring).to_a)
end

#cwdPathname

Working directory of the remote vim session

Returns:

  • (Pathname)


123
124
125
# File 'lib/appear/editor/nvim.rb', line 123

def cwd
  expr('getcwd()')
end

#drop(filename) ⇒ Object

Open a file in vim, or focus a window editing this file, if it’s already open. Vim has a command a lot like this, but I can’t get it to work in either of [vim,nvim] the way the docs say it should. That’s why it’s re-implemented here.

Parameters:

  • filename (String)


178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/appear/editor/nvim.rb', line 178

def drop(filename)
  # not using find_buffer because we care about panes; we'll have to open
  # a new one if one doesn't exist anyways.
  pane = find_pane(filename)

  if pane
    reveal_pane(pane)
    return pane
  end

  # TODO: consider options other than vsplit
  # TODO: such as opening in the main window with :edit if the main
  # window is an empty [NoName] buffer, from a new vim maybe?
  cmd("vertical split #{filename.shellescape}")
  find_pane(filename)
end

#expr(vimstring) ⇒ Object

evaluate a Vimscript expression

Parameters:

  • vimstring (String)

    the expression, eg “fnamemodify(‘~’, ‘:p’)”

Returns:

  • (Object)

    expression result, parsed as YAML.



100
101
102
103
104
# File 'lib/appear/editor/nvim.rb', line 100

def expr(vimstring)
  @expr_memo.call(vimstring) do
    parse_output_as_yaml(run(command.flag('remote-expr', vimstring).to_a))
  end
end

#find_buffer(filename) ⇒ Hash?

Find the buffer for a given filename.

Parameters:

  • filename (String)

Returns:

  • (Hash, nil)

    buffer info, nil if not found



153
154
155
156
157
158
# File 'lib/appear/editor/nvim.rb', line 153

def find_buffer(filename)
  p = File.expand_path(filename)
  get_buffers.find do |buffer|
    buffer[:absolute_path] == p
  end
end

#find_pane(filename) ⇒ Pane?

Find the pane for a given filename.

Parameters:

  • filename (String)

Returns:

  • (Pane, nil)

    nil if not found



164
165
166
167
168
169
170
# File 'lib/appear/editor/nvim.rb', line 164

def find_pane(filename)
  p = Pathname.new(filename).expand_path.to_s
  panes.find do |pane|
    buff = pane.buffer_info
    buff[:absolute_path] == p
  end
end

#panesArray<Pane>

Get all the Vim panes in all tabs.

Returns:

  • (Array<Pane>)

    data



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/appear/editor/nvim.rb', line 130

def panes
  @expr_memo.call(nil, 'panes') do
    all_buffers = get_buffers
    all_panes = []
    get_windows.each_with_index do |wins, tab_idx|
      wins.each_with_index do |buffer, win_idx|
        all_panes << Pane.new(
          # in Vim, tabs and windows start indexing at 1
          :tab => tab_idx + 1,
          :window => win_idx + 1,
          :buffer => buffer,
          :buffer_info => all_buffers[buffer - 1]
        )
      end
    end
    all_panes
  end
end

#pidFixnum

PID of the remote vim session

Returns:

  • (Fixnum)


116
117
118
# File 'lib/appear/editor/nvim.rb', line 116

def pid
  expr('getpid()')
end

#reveal_pane(pane) ⇒ Object

Reveal a pane in Nvim

Parameters:



198
199
200
201
202
203
# File 'lib/appear/editor/nvim.rb', line 198

def reveal_pane(pane)
  # go to tab
  cmd("tabnext #{pane.tab}")
  # go to window
  cmd("#{pane.window} . wincmd w")
end

#to_sString

Description of this Neovim socket and session.

Returns:

  • (String)


207
208
209
# File 'lib/appear/editor/nvim.rb', line 207

def to_s
  "#<#{self.class.name}:0x#{'%x' % (object_id << 1)} in #{cwd.inspect}>"
end