From cbe3e047452843c5d76b494466f5e1df9d9524bf Mon Sep 17 00:00:00 2001 From: micbou Date: Tue, 27 Oct 2015 17:00:11 +0100 Subject: [PATCH] Add :YcmToggleLogs command --- autoload/youcompleteme.vim | 15 ++++++ python/ycm/vimsupport.py | 93 +++++++++++++++++++++++++++++++++++-- python/ycm/youcompleteme.py | 39 ++++++++++++++++ 3 files changed, 143 insertions(+), 4 deletions(-) diff --git a/autoload/youcompleteme.vim b/autoload/youcompleteme.vim index 07700ba2..4eaedb48 100644 --- a/autoload/youcompleteme.vim +++ b/autoload/youcompleteme.vim @@ -310,6 +310,8 @@ function! s:SetUpCommands() command! YcmRestartServer call s:RestartServer() command! YcmShowDetailedDiagnostic call s:ShowDetailedDiagnostic() command! YcmDebugInfo call s:DebugInfo() + command! -nargs=? -complete=custom,youcompleteme#LogsComplete + \ YcmToggleLogs call s:ToggleLogs() command! -nargs=* -complete=custom,youcompleteme#SubCommandsComplete \ YcmCompleter call s:CompleterCommand() command! YcmForceCompileAndDiagnostics call s:ForceCompileAndDiagnostics() @@ -763,6 +765,14 @@ function! s:DebugInfo() endfunction +function! s:ToggleLogs(...) + let stderr = a:0 == 0 || a:1 !=? 'Stdout' + let stdout = a:0 == 0 || a:1 !=? 'Stderr' + py ycm_state.ToggleLogs( stdout = vimsupport.GetBoolValue( 'l:stdout' ), + \ stderr = vimsupport.GetBoolValue( 'l:stderr' ) ) +endfunction + + function! s:CompleterCommand(...) " CompleterCommand will call the OnUserCommand function of a completer. " If the first arguments is of the form "ft=..." it can be used to specify the @@ -796,6 +806,11 @@ function! youcompleteme#OpenGoToList() endfunction +function! youcompleteme#LogsComplete( arglead, cmdline, cursorpos ) + return "Stdout\nStderr" +endfunction + + function! youcompleteme#SubCommandsComplete( arglead, cmdline, cursorpos ) return join( pyeval( 'ycm_state.GetDefinedSubcommands()' ), \ "\n") diff --git a/python/ycm/vimsupport.py b/python/ycm/vimsupport.py index 1ade1706..cca72940 100644 --- a/python/ycm/vimsupport.py +++ b/python/ycm/vimsupport.py @@ -331,9 +331,9 @@ def TryJumpLocationInOpenedTab( filename, line, column ): return False -# Maps User jump command to vim jump command -def GetVimJumpCommand( user_command ): - vim_command = BUFFER_COMMAND_MAP.get( user_command, 'edit' ) +# Maps User command to vim command +def GetVimCommand( user_command, default = 'edit' ): + vim_command = BUFFER_COMMAND_MAP.get( user_command, default ) if vim_command == 'edit' and not BufferIsUsable( vim.current.buffer ): vim_command = 'split' return vim_command @@ -358,7 +358,7 @@ def JumpToLocation( filename, line, column ): return user_command = 'new-tab' - vim_command = GetVimJumpCommand( user_command ) + vim_command = GetVimCommand( user_command ) try: vim.command( 'keepjumps {0} {1}'.format( vim_command, EscapedFilepath( filename ) ) ) @@ -610,6 +610,11 @@ def JumpToPreviousWindow(): vim.command( 'silent! wincmd p' ) +def JumpToTab( tab_number ): + """Jump to Vim tab with corresponding number """ + vim.command( 'silent! tabn {0}'.format( tab_number ) ) + + def OpenFileInPreviewWindow( filename ): """ Open the supplied filename in the preview window """ vim.command( 'silent! pedit! ' + filename ) @@ -653,3 +658,83 @@ def WriteToPreviewWindow( message ): # the information we have. The only remaining option is to echo to the # status area. EchoText( message ) + + +def CheckFilename( filename ): + """Check if filename is openable.""" + try: + open( filename ).close() + except TypeError: + raise RuntimeError( "'{0}' is not a valid filename".format( filename ) ) + except IOError as error: + raise RuntimeError( + "filename '{0}' cannot be opened. {1}".format( filename, error ) ) + + +def BufferExistsForFilename( filename ): + """Check if a buffer exists for a specific file.""" + return GetBufferNumberForFilename( filename, False ) is not -1 + + +def CloseBuffersForFilename( filename ): + """Close all buffers for a specific file.""" + buffer_number = GetBufferNumberForFilename( filename, False ) + while buffer_number is not -1: + vim.command( 'silent! bwipeout! {0}'.format( buffer_number ) ) + buffer_number = GetBufferNumberForFilename( filename, False ) + + +def OpenFilename( filename, options = {} ): + """Open a file in Vim. Following options are available: + - command: specify which Vim command is used to open the file. Choices + are same-buffer, horizontal-split, vertical-split, and new-tab (default: + horizontal-split); + - size: set the height of the window for a horizontal split or the width for + a vertical one (default: ''); + - fix: set the winfixheight option for a horizontal split or winfixwidth for + a vertical one (default: False). See :h winfix for details; + - focus: focus the opened file (default: False); + - watch: automatically watch for changes (default: False). This is useful + for logs; + - position: set the position where the file is opened (default: start). + Choices are start and end.""" + + # Set the options. + command = GetVimCommand( options.get( 'command', 'horizontal-split' ), + 'horizontal-split' ) + size = ( options.get( 'size', '' ) if command in [ 'split', 'vsplit' ] else + '' ) + focus = options.get( 'focus', False ) + watch = options.get( 'watch', False ) + position = options.get( 'position', 'start' ) + + # There is no command in Vim to return to the previous tab so we need to + # remember the current tab if needed. + if not focus and command is 'tabedit': + previous_tab = GetIntValue( 'tabpagenr()' ) + + # Open the file + CheckFilename( filename ) + vim.command( 'silent! {0}{1} {2}'.format( size, command, filename ) ) + + if command is 'split': + vim.current.window.options[ 'winfixheight' ] = options.get( 'fix', False ) + if command is 'vsplit': + vim.current.window.options[ 'winfixwidth' ] = options.get( 'fix', False ) + + if watch: + vim.current.buffer.options[ 'autoread' ] = True + vim.command( "exec 'au BufEnter :silent! checktime {0}'" + .format( filename ) ) + + if position is 'end': + vim.command( 'silent! normal G zz' ) + + # Vim automatically set the focus to the opened file so we need to get the + # focus back (if the focus option is disabled) when opening a new tab or + # window. + if not focus: + if command is 'tabedit': + JumpToTab( previous_tab ) + if command in [ 'split', 'vsplit' ]: + JumpToPreviousWindow() diff --git a/python/ycm/youcompleteme.py b/python/ycm/youcompleteme.py index 6dd1778c..0df4a1d4 100644 --- a/python/ycm/youcompleteme.py +++ b/python/ycm/youcompleteme.py @@ -176,6 +176,7 @@ class YouCompleteMe( object ): def RestartServer( self ): + self._CloseLogs() vimsupport.PostVimMessage( 'Restarting ycmd server...' ) self._user_notified_about_crash = False self._ServerCleanup() @@ -507,6 +508,44 @@ class YouCompleteMe( object ): return debug_info + def _OpenLogs( self, stdout = True, stderr = True ): + # Open log files in a horizontal window with the same behavior as the + # preview window (same height and winfixheight enabled). Automatically + # watch for changes. Set the cursor position at the end of the file. + options = { + 'size': vimsupport.GetIntValue( '&previewheight' ), + 'fix': True, + 'watch': True, + 'position': 'end' + } + + if stdout: + vimsupport.OpenFilename( self._server_stdout, options ) + if stderr: + vimsupport.OpenFilename( self._server_stderr, options ) + + + def _CloseLogs( self, stdout = True, stderr = True ): + if stdout: + vimsupport.CloseBuffersForFilename( self._server_stdout ) + if stderr: + vimsupport.CloseBuffersForFilename( self._server_stderr ) + + + def ToggleLogs( self, stdout = True, stderr = True ): + if ( stdout and + vimsupport.BufferExistsForFilename( self._server_stdout ) or + stderr and + vimsupport.BufferExistsForFilename( self._server_stderr ) ): + return self._CloseLogs( stdout = stdout, stderr = stderr ) + + try: + self._OpenLogs( stdout = stdout, stderr = stderr ) + except RuntimeError as error: + vimsupport.PostVimMessage( 'YouCompleteMe encountered an error when ' + 'opening logs: {0}.'.format( error ) ) + + def CurrentFiletypeCompletionEnabled( self ): filetypes = vimsupport.CurrentFiletypes() filetype_to_disable = self._user_options[