mirror of https://github.com/akelge/vim
moved plugins to Vundle
This commit is contained in:
parent
d1e2801be5
commit
35911ffb93
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,319 +0,0 @@
|
|||
# FILE: autoload/conque_term/conque_globals.py
|
||||
# AUTHOR: Nico Raffo <nicoraffo@gmail.com>
|
||||
# WEBSITE: http://conque.googlecode.com
|
||||
# MODIFIED: 2011-08-12
|
||||
# VERSION: 2.2, for Vim 7.0
|
||||
# LICENSE:
|
||||
# Conque - Vim terminal/console emulator
|
||||
# Copyright (C) 2009-__YEAR__ Nico Raffo
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""Common global constants and functions for Conque."""
|
||||
|
||||
import sys
|
||||
import re
|
||||
import os # DEBUG
|
||||
|
||||
import traceback # DEBUG
|
||||
|
||||
# PYTHON VERSION
|
||||
CONQUE_PYTHON_VERSION = sys.version_info[0]
|
||||
|
||||
# Encoding
|
||||
|
||||
try:
|
||||
# Vim's character encoding
|
||||
import vim
|
||||
CONQUE_VIM_ENCODING = vim.eval('&encoding')
|
||||
|
||||
except:
|
||||
CONQUE_VIM_ENCODING = 'utf-8'
|
||||
|
||||
|
||||
def u(str_val, str_encoding='utf-8', errors='strict'):
|
||||
""" Foolhardy attempt to make unicode string syntax compatible with both python 2 and 3. """
|
||||
|
||||
if not str_val:
|
||||
str_val = ''
|
||||
|
||||
if CONQUE_PYTHON_VERSION == 3:
|
||||
return str_val
|
||||
|
||||
else:
|
||||
return unicode(str_val, str_encoding, errors)
|
||||
|
||||
def uchr(str):
|
||||
""" Foolhardy attempt to make unicode string syntax compatible with both python 2 and 3. """
|
||||
|
||||
if CONQUE_PYTHON_VERSION == 3:
|
||||
return chr(str)
|
||||
|
||||
else:
|
||||
return unichr(str)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Unix escape sequence settings
|
||||
|
||||
CONQUE_CTL = {
|
||||
1: 'soh', # start of heading
|
||||
2: 'stx', # start of text
|
||||
7: 'bel', # bell
|
||||
8: 'bs', # backspace
|
||||
9: 'tab', # tab
|
||||
10: 'nl', # new line
|
||||
13: 'cr', # carriage return
|
||||
14: 'so', # shift out
|
||||
15: 'si' # shift in
|
||||
}
|
||||
# 11 : 'vt', # vertical tab
|
||||
# 12 : 'ff', # form feed
|
||||
|
||||
# Escape sequences
|
||||
CONQUE_ESCAPE = {
|
||||
'm': 'font',
|
||||
'J': 'clear_screen',
|
||||
'K': 'clear_line',
|
||||
'@': 'add_spaces',
|
||||
'A': 'cursor_up',
|
||||
'B': 'cursor_down',
|
||||
'C': 'cursor_right',
|
||||
'D': 'cursor_left',
|
||||
'G': 'cursor_to_column',
|
||||
'H': 'cursor',
|
||||
'P': 'delete_chars',
|
||||
'f': 'cursor',
|
||||
'g': 'tab_clear',
|
||||
'r': 'set_coords',
|
||||
'h': 'set',
|
||||
'l': 'reset'
|
||||
}
|
||||
# 'L': 'insert_lines',
|
||||
# 'M': 'delete_lines',
|
||||
# 'd': 'cusor_vpos',
|
||||
|
||||
# Alternate escape sequences, no [
|
||||
CONQUE_ESCAPE_PLAIN = {
|
||||
'D': 'scroll_up',
|
||||
'E': 'next_line',
|
||||
'H': 'set_tab',
|
||||
'M': 'scroll_down'
|
||||
}
|
||||
# 'N': 'single_shift_2',
|
||||
# 'O': 'single_shift_3',
|
||||
# '=': 'alternate_keypad',
|
||||
# '>': 'numeric_keypad',
|
||||
# '7': 'save_cursor',
|
||||
# '8': 'restore_cursor',
|
||||
|
||||
# Character set escape sequences, with "("
|
||||
CONQUE_ESCAPE_CHARSET = {
|
||||
'A': 'uk',
|
||||
'B': 'us',
|
||||
'0': 'graphics'
|
||||
}
|
||||
|
||||
# Uber alternate escape sequences, with # or ?
|
||||
CONQUE_ESCAPE_QUESTION = {
|
||||
'1h': 'new_line_mode',
|
||||
'3h': '132_cols',
|
||||
'4h': 'smooth_scrolling',
|
||||
'5h': 'reverse_video',
|
||||
'6h': 'relative_origin',
|
||||
'7h': 'set_auto_wrap',
|
||||
'8h': 'set_auto_repeat',
|
||||
'9h': 'set_interlacing_mode',
|
||||
'1l': 'set_cursor_key',
|
||||
'2l': 'set_vt52',
|
||||
'3l': '80_cols',
|
||||
'4l': 'set_jump_scrolling',
|
||||
'5l': 'normal_video',
|
||||
'6l': 'absolute_origin',
|
||||
'7l': 'reset_auto_wrap',
|
||||
'8l': 'reset_auto_repeat',
|
||||
'9l': 'reset_interlacing_mode'
|
||||
}
|
||||
|
||||
CONQUE_ESCAPE_HASH = {
|
||||
'8': 'screen_alignment_test'
|
||||
}
|
||||
# '3': 'double_height_top',
|
||||
# '4': 'double_height_bottom',
|
||||
# '5': 'single_height_single_width',
|
||||
# '6': 'single_height_double_width',
|
||||
|
||||
CONQUE_GRAPHICS_SET = [
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
|
||||
0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
|
||||
0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
|
||||
0x0028, 0x0029, 0x002A, 0x2192, 0x2190, 0x2191, 0x2193, 0x002F,
|
||||
0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
|
||||
0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
|
||||
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
||||
0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
|
||||
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
|
||||
0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x00A0,
|
||||
0x25C6, 0x2592, 0x2409, 0x240C, 0x240D, 0x240A, 0x00B0, 0x00B1,
|
||||
0x2591, 0x240B, 0x2518, 0x2510, 0x250C, 0x2514, 0x253C, 0xF800,
|
||||
0xF801, 0x2500, 0xF803, 0xF804, 0x251C, 0x2524, 0x2534, 0x252C,
|
||||
0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00B7, 0x007F,
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
|
||||
0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
|
||||
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
|
||||
0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
|
||||
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
|
||||
0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
|
||||
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
|
||||
0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
|
||||
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
|
||||
0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
|
||||
0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
|
||||
0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
|
||||
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
|
||||
0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
|
||||
0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
|
||||
0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
|
||||
]
|
||||
|
||||
# Font codes
|
||||
CONQUE_FONT = {
|
||||
0: {'description': 'Normal (default)', 'attributes': {'cterm': 'NONE', 'ctermfg': 'NONE', 'ctermbg': 'NONE', 'gui': 'NONE', 'guifg': 'NONE', 'guibg': 'NONE'}, 'normal': True},
|
||||
1: {'description': 'Bold', 'attributes': {'cterm': 'BOLD', 'gui': 'BOLD'}, 'normal': False},
|
||||
4: {'description': 'Underlined', 'attributes': {'cterm': 'UNDERLINE', 'gui': 'UNDERLINE'}, 'normal': False},
|
||||
5: {'description': 'Blink (appears as Bold)', 'attributes': {'cterm': 'BOLD', 'gui': 'BOLD'}, 'normal': False},
|
||||
7: {'description': 'Inverse', 'attributes': {'cterm': 'REVERSE', 'gui': 'REVERSE'}, 'normal': False},
|
||||
8: {'description': 'Invisible (hidden)', 'attributes': {'ctermfg': '0', 'ctermbg': '0', 'guifg': '#000000', 'guibg': '#000000'}, 'normal': False},
|
||||
22: {'description': 'Normal (neither bold nor faint)', 'attributes': {'cterm': 'NONE', 'gui': 'NONE'}, 'normal': True},
|
||||
24: {'description': 'Not underlined', 'attributes': {'cterm': 'NONE', 'gui': 'NONE'}, 'normal': True},
|
||||
25: {'description': 'Steady (not blinking)', 'attributes': {'cterm': 'NONE', 'gui': 'NONE'}, 'normal': True},
|
||||
27: {'description': 'Positive (not inverse)', 'attributes': {'cterm': 'NONE', 'gui': 'NONE'}, 'normal': True},
|
||||
28: {'description': 'Visible (not hidden)', 'attributes': {'ctermfg': 'NONE', 'ctermbg': 'NONE', 'guifg': 'NONE', 'guibg': 'NONE'}, 'normal': True},
|
||||
30: {'description': 'Set foreground color to Black', 'attributes': {'ctermfg': '16', 'guifg': '#000000'}, 'normal': False},
|
||||
31: {'description': 'Set foreground color to Red', 'attributes': {'ctermfg': '1', 'guifg': '#ff0000'}, 'normal': False},
|
||||
32: {'description': 'Set foreground color to Green', 'attributes': {'ctermfg': '2', 'guifg': '#00ff00'}, 'normal': False},
|
||||
33: {'description': 'Set foreground color to Yellow', 'attributes': {'ctermfg': '3', 'guifg': '#ffff00'}, 'normal': False},
|
||||
34: {'description': 'Set foreground color to Blue', 'attributes': {'ctermfg': '4', 'guifg': '#0000ff'}, 'normal': False},
|
||||
35: {'description': 'Set foreground color to Magenta', 'attributes': {'ctermfg': '5', 'guifg': '#990099'}, 'normal': False},
|
||||
36: {'description': 'Set foreground color to Cyan', 'attributes': {'ctermfg': '6', 'guifg': '#009999'}, 'normal': False},
|
||||
37: {'description': 'Set foreground color to White', 'attributes': {'ctermfg': '7', 'guifg': '#ffffff'}, 'normal': False},
|
||||
39: {'description': 'Set foreground color to default (original)', 'attributes': {'ctermfg': 'NONE', 'guifg': 'NONE'}, 'normal': True},
|
||||
40: {'description': 'Set background color to Black', 'attributes': {'ctermbg': '16', 'guibg': '#000000'}, 'normal': False},
|
||||
41: {'description': 'Set background color to Red', 'attributes': {'ctermbg': '1', 'guibg': '#ff0000'}, 'normal': False},
|
||||
42: {'description': 'Set background color to Green', 'attributes': {'ctermbg': '2', 'guibg': '#00ff00'}, 'normal': False},
|
||||
43: {'description': 'Set background color to Yellow', 'attributes': {'ctermbg': '3', 'guibg': '#ffff00'}, 'normal': False},
|
||||
44: {'description': 'Set background color to Blue', 'attributes': {'ctermbg': '4', 'guibg': '#0000ff'}, 'normal': False},
|
||||
45: {'description': 'Set background color to Magenta', 'attributes': {'ctermbg': '5', 'guibg': '#990099'}, 'normal': False},
|
||||
46: {'description': 'Set background color to Cyan', 'attributes': {'ctermbg': '6', 'guibg': '#009999'}, 'normal': False},
|
||||
47: {'description': 'Set background color to White', 'attributes': {'ctermbg': '7', 'guibg': '#ffffff'}, 'normal': False},
|
||||
49: {'description': 'Set background color to default (original).', 'attributes': {'ctermbg': 'NONE', 'guibg': 'NONE'}, 'normal': True},
|
||||
90: {'description': 'Set foreground color to Black', 'attributes': {'ctermfg': '8', 'guifg': '#000000'}, 'normal': False},
|
||||
91: {'description': 'Set foreground color to Red', 'attributes': {'ctermfg': '9', 'guifg': '#ff0000'}, 'normal': False},
|
||||
92: {'description': 'Set foreground color to Green', 'attributes': {'ctermfg': '10', 'guifg': '#00ff00'}, 'normal': False},
|
||||
93: {'description': 'Set foreground color to Yellow', 'attributes': {'ctermfg': '11', 'guifg': '#ffff00'}, 'normal': False},
|
||||
94: {'description': 'Set foreground color to Blue', 'attributes': {'ctermfg': '12', 'guifg': '#0000ff'}, 'normal': False},
|
||||
95: {'description': 'Set foreground color to Magenta', 'attributes': {'ctermfg': '13', 'guifg': '#990099'}, 'normal': False},
|
||||
96: {'description': 'Set foreground color to Cyan', 'attributes': {'ctermfg': '14', 'guifg': '#009999'}, 'normal': False},
|
||||
97: {'description': 'Set foreground color to White', 'attributes': {'ctermfg': '15', 'guifg': '#ffffff'}, 'normal': False},
|
||||
100: {'description': 'Set background color to Black', 'attributes': {'ctermbg': '8', 'guibg': '#000000'}, 'normal': False},
|
||||
101: {'description': 'Set background color to Red', 'attributes': {'ctermbg': '9', 'guibg': '#ff0000'}, 'normal': False},
|
||||
102: {'description': 'Set background color to Green', 'attributes': {'ctermbg': '10', 'guibg': '#00ff00'}, 'normal': False},
|
||||
103: {'description': 'Set background color to Yellow', 'attributes': {'ctermbg': '11', 'guibg': '#ffff00'}, 'normal': False},
|
||||
104: {'description': 'Set background color to Blue', 'attributes': {'ctermbg': '12', 'guibg': '#0000ff'}, 'normal': False},
|
||||
105: {'description': 'Set background color to Magenta', 'attributes': {'ctermbg': '13', 'guibg': '#990099'}, 'normal': False},
|
||||
106: {'description': 'Set background color to Cyan', 'attributes': {'ctermbg': '14', 'guibg': '#009999'}, 'normal': False},
|
||||
107: {'description': 'Set background color to White', 'attributes': {'ctermbg': '15', 'guibg': '#ffffff'}, 'normal': False}
|
||||
}
|
||||
|
||||
|
||||
# regular expression matching (almost) all control sequences
|
||||
CONQUE_SEQ_REGEX = re.compile("(\x1b\[?\??#?[0-9;]*[a-zA-Z0-9@=>]|\x1b\][0-9];.*?\x07|[\x01-\x0f]|\x1b\([AB0])")
|
||||
CONQUE_SEQ_REGEX_CTL = re.compile("^[\x01-\x0f]$")
|
||||
CONQUE_SEQ_REGEX_CSI = re.compile("^\x1b\[")
|
||||
CONQUE_SEQ_REGEX_TITLE = re.compile("^\x1b\]")
|
||||
CONQUE_SEQ_REGEX_HASH = re.compile("^\x1b#")
|
||||
CONQUE_SEQ_REGEX_ESC = re.compile("^\x1b.$")
|
||||
CONQUE_SEQ_REGEX_CHAR = re.compile("^\x1b[()]")
|
||||
|
||||
# match table output
|
||||
CONQUE_TABLE_OUTPUT = re.compile("^\s*\|\s.*\s\|\s*$|^\s*\+[=+-]+\+\s*$")
|
||||
|
||||
# basic terminal colors
|
||||
CONQUE_COLOR_SEQUENCE = (
|
||||
'000', '009', '090', '099', '900', '909', '990', '999',
|
||||
'000', '00f', '0f0', '0ff', 'f00', 'f0f', 'ff0', 'fff'
|
||||
)
|
||||
|
||||
|
||||
# Windows subprocess constants
|
||||
|
||||
# shared memory size
|
||||
CONQUE_SOLE_BUFFER_LENGTH = 1000
|
||||
CONQUE_SOLE_INPUT_SIZE = 1000
|
||||
CONQUE_SOLE_STATS_SIZE = 1000
|
||||
CONQUE_SOLE_COMMANDS_SIZE = 255
|
||||
CONQUE_SOLE_RESCROLL_SIZE = 255
|
||||
CONQUE_SOLE_RESIZE_SIZE = 255
|
||||
|
||||
# interval of screen redraw
|
||||
# larger number means less frequent
|
||||
CONQUE_SOLE_SCREEN_REDRAW = 50
|
||||
|
||||
# interval of full buffer redraw
|
||||
# larger number means less frequent
|
||||
CONQUE_SOLE_BUFFER_REDRAW = 500
|
||||
|
||||
# interval of full output bucket replacement
|
||||
# larger number means less frequent, 1 = every time
|
||||
CONQUE_SOLE_MEM_REDRAW = 1000
|
||||
|
||||
# maximum number of lines with terminal colors
|
||||
# ignored if g:ConqueTerm_Color = 2
|
||||
CONQUE_MAX_SYNTAX_LINES = 200
|
||||
|
||||
# windows input splitting on special keys
|
||||
CONQUE_WIN32_REGEX_VK = re.compile("(\x1b\[[0-9;]+VK)")
|
||||
|
||||
# windows attribute string splitting
|
||||
CONQUE_WIN32_REGEX_ATTR = re.compile("((.)\\2*)", re.DOTALL)
|
||||
|
||||
# special key attributes
|
||||
CONQUE_VK_ATTR_CTRL_PRESSED = u('1024')
|
||||
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
# FILE: autoload/conque_term/conque_screen.py
|
||||
# AUTHOR: Nico Raffo <nicoraffo@gmail.com>
|
||||
# WEBSITE: http://conque.googlecode.com
|
||||
# MODIFIED: 2011-08-12
|
||||
# VERSION: 2.2, for Vim 7.0
|
||||
# LICENSE:
|
||||
# Conque - Vim terminal/console emulator
|
||||
# Copyright (C) 2009-__YEAR__ Nico Raffo
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""
|
||||
ConqueScreen is an extention of the vim.current.buffer object
|
||||
|
||||
Unix terminal escape sequences usually reference line numbers relative to the
|
||||
top of the visible screen. However the visible portion of the Vim buffer
|
||||
representing the terminal probably doesn't start at the first line of the
|
||||
buffer.
|
||||
|
||||
The ConqueScreen class allows access to the Vim buffer with screen-relative
|
||||
line numbering. And handles a few other related tasks, such as setting the
|
||||
correct cursor position.
|
||||
|
||||
E.g.:
|
||||
s = ConqueScreen()
|
||||
...
|
||||
s[5] = 'Set 5th line in terminal to this line'
|
||||
s.append('Add new line to terminal')
|
||||
s[5] = 'Since previous append() command scrolled the terminal down, this is a different line than first cb[5] call'
|
||||
|
||||
"""
|
||||
|
||||
import vim
|
||||
|
||||
|
||||
class ConqueScreen(object):
|
||||
|
||||
# the buffer
|
||||
buffer = None
|
||||
|
||||
# screen and scrolling regions
|
||||
screen_top = 1
|
||||
|
||||
# screen width
|
||||
screen_width = 80
|
||||
screen_height = 80
|
||||
|
||||
# char encoding for vim buffer
|
||||
screen_encoding = 'utf-8'
|
||||
|
||||
|
||||
def __init__(self):
|
||||
""" Initialize screen size and character encoding. """
|
||||
|
||||
self.buffer = vim.current.buffer
|
||||
|
||||
# initialize screen size
|
||||
self.screen_top = 1
|
||||
self.screen_width = vim.current.window.width
|
||||
self.screen_height = vim.current.window.height
|
||||
|
||||
# save screen character encoding type
|
||||
self.screen_encoding = vim.eval('&fileencoding')
|
||||
|
||||
|
||||
def __len__(self):
|
||||
""" Define the len() function for ConqueScreen objects. """
|
||||
return len(self.buffer)
|
||||
|
||||
|
||||
def __getitem__(self, key):
|
||||
""" Define value access for ConqueScreen objects. """
|
||||
buffer_line = self.get_real_idx(key)
|
||||
|
||||
# if line is past buffer end, add lines to buffer
|
||||
if buffer_line >= len(self.buffer):
|
||||
for i in range(len(self.buffer), buffer_line + 1):
|
||||
self.append(' ')
|
||||
|
||||
return u(self.buffer[buffer_line], 'utf-8')
|
||||
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
""" Define value assignments for ConqueScreen objects. """
|
||||
buffer_line = self.get_real_idx(key)
|
||||
|
||||
if CONQUE_PYTHON_VERSION == 2:
|
||||
val = value.encode(self.screen_encoding)
|
||||
else:
|
||||
# XXX / Vim's python3 interface doesn't accept bytes object
|
||||
val = str(value)
|
||||
|
||||
# if line is past end of screen, append
|
||||
if buffer_line == len(self.buffer):
|
||||
self.buffer.append(val)
|
||||
else:
|
||||
self.buffer[buffer_line] = val
|
||||
|
||||
|
||||
def __delitem__(self, key):
|
||||
""" Define value deletion for ConqueScreen objects. """
|
||||
del self.buffer[self.screen_top + key - 2]
|
||||
|
||||
|
||||
def append(self, value):
|
||||
""" Define value appending for ConqueScreen objects. """
|
||||
|
||||
if len(self.buffer) > self.screen_top + self.screen_height - 1:
|
||||
self.buffer[len(self.buffer) - 1] = value
|
||||
else:
|
||||
self.buffer.append(value)
|
||||
|
||||
if len(self.buffer) > self.screen_top + self.screen_height - 1:
|
||||
self.screen_top += 1
|
||||
|
||||
if vim.current.buffer.number == self.buffer.number:
|
||||
vim.command('normal! G')
|
||||
|
||||
|
||||
def insert(self, line, value):
|
||||
""" Define value insertion for ConqueScreen objects. """
|
||||
|
||||
l = self.screen_top + line - 2
|
||||
self.buffer.append(value, l)
|
||||
|
||||
|
||||
def get_top(self):
|
||||
""" Get the Vim line number representing the top of the visible terminal. """
|
||||
return self.screen_top
|
||||
|
||||
|
||||
def get_real_idx(self, line):
|
||||
""" Get the zero index Vim line number corresponding to the provided screen line. """
|
||||
return (self.screen_top + line - 2)
|
||||
|
||||
|
||||
def get_buffer_line(self, line):
|
||||
""" Get the Vim line number corresponding to the provided screen line. """
|
||||
return (self.screen_top + line - 1)
|
||||
|
||||
|
||||
def set_screen_width(self, width):
|
||||
""" Set the screen width. """
|
||||
self.screen_width = width
|
||||
|
||||
|
||||
def clear(self):
|
||||
""" Clear the screen. Does not clear the buffer, just scrolls down past all text. """
|
||||
|
||||
self.screen_width = width
|
||||
self.buffer.append(' ')
|
||||
vim.command('normal! Gzt')
|
||||
self.screen_top = len(self.buffer)
|
||||
|
||||
|
||||
def set_cursor(self, line, column):
|
||||
""" Set cursor position. """
|
||||
|
||||
# figure out line
|
||||
buffer_line = self.screen_top + line - 1
|
||||
if buffer_line > len(self.buffer):
|
||||
for l in range(len(self.buffer) - 1, buffer_line):
|
||||
self.buffer.append('')
|
||||
|
||||
# figure out column
|
||||
real_column = column
|
||||
if len(self.buffer[buffer_line - 1]) < real_column:
|
||||
self.buffer[buffer_line - 1] = self.buffer[buffer_line - 1] + ' ' * (real_column - len(self.buffer[buffer_line - 1]))
|
||||
|
||||
if not CONQUE_FAST_MODE:
|
||||
# set cursor at byte index of real_column'th character
|
||||
vim.command('call cursor(' + str(buffer_line) + ', byteidx(getline(' + str(buffer_line) + '), ' + str(real_column) + '))')
|
||||
|
||||
else:
|
||||
# old version
|
||||
# python version is occasionally grumpy
|
||||
try:
|
||||
vim.current.window.cursor = (buffer_line, real_column - 1)
|
||||
except:
|
||||
vim.command('call cursor(' + str(buffer_line) + ', ' + str(real_column) + ')')
|
||||
|
||||
|
||||
def reset_size(self, line):
|
||||
""" Change screen size """
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# save cursor line number
|
||||
buffer_line = self.screen_top + line
|
||||
|
||||
# reset screen size
|
||||
self.screen_width = vim.current.window.width
|
||||
self.screen_height = vim.current.window.height
|
||||
self.screen_top = len(self.buffer) - vim.current.window.height + 1
|
||||
if self.screen_top < 1:
|
||||
self.screen_top = 1
|
||||
|
||||
|
||||
# align bottom of buffer to bottom of screen
|
||||
vim.command('normal! ' + str(self.screen_height) + 'kG')
|
||||
|
||||
# return new relative line number
|
||||
return (buffer_line - self.screen_top)
|
||||
|
||||
|
||||
def align(self):
|
||||
""" align bottom of buffer to bottom of screen """
|
||||
vim.command('normal! ' + str(self.screen_height) + 'kG')
|
||||
|
||||
|
|
@ -1,458 +0,0 @@
|
|||
# FILE: autoload/conque_term/conque_sole.py
|
||||
# AUTHOR: Nico Raffo <nicoraffo@gmail.com>
|
||||
# WEBSITE: http://conque.googlecode.com
|
||||
# MODIFIED: 2011-08-12
|
||||
# VERSION: 2.2, for Vim 7.0
|
||||
# LICENSE:
|
||||
# Conque - Vim terminal/console emulator
|
||||
# Copyright (C) 2009-__YEAR__ Nico Raffo
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""
|
||||
Windows Console Emulator
|
||||
|
||||
This is the main interface to the Windows emulator. It reads new output from the background console
|
||||
and updates the Vim buffer.
|
||||
"""
|
||||
|
||||
import vim
|
||||
|
||||
|
||||
class ConqueSole(Conque):
|
||||
|
||||
window_top = None
|
||||
window_bottom = None
|
||||
|
||||
color_cache = {}
|
||||
attribute_cache = {}
|
||||
color_mode = None
|
||||
color_conceals = {}
|
||||
|
||||
buffer = None
|
||||
encoding = None
|
||||
|
||||
# counters for periodic rendering
|
||||
buffer_redraw_ct = 1
|
||||
screen_redraw_ct = 1
|
||||
|
||||
# line offset, shifts output down
|
||||
offset = 0
|
||||
|
||||
|
||||
def open(self):
|
||||
""" Start command and initialize this instance
|
||||
|
||||
Arguments:
|
||||
command - Command string, e.g. "Powershell.exe"
|
||||
options - Dictionary of config options
|
||||
python_exe - Path to the python.exe executable. Usually C:\PythonXX\python.exe
|
||||
communicator_py - Path to subprocess controller script in user's vimfiles directory
|
||||
|
||||
"""
|
||||
# get arguments
|
||||
command = vim.eval('command')
|
||||
options = vim.eval('options')
|
||||
python_exe = vim.eval('py_exe')
|
||||
communicator_py = vim.eval('py_vim')
|
||||
|
||||
# init size
|
||||
self.columns = vim.current.window.width
|
||||
self.lines = vim.current.window.height
|
||||
self.window_top = 0
|
||||
self.window_bottom = vim.current.window.height - 1
|
||||
|
||||
# color mode
|
||||
self.color_mode = vim.eval('g:ConqueTerm_ColorMode')
|
||||
|
||||
# line offset
|
||||
self.offset = int(options['offset'])
|
||||
|
||||
# init color
|
||||
self.enable_colors = options['color'] and not CONQUE_FAST_MODE
|
||||
|
||||
# open command
|
||||
self.proc = ConqueSoleWrapper()
|
||||
self.proc.open(command, self.lines, self.columns, python_exe, communicator_py, options)
|
||||
|
||||
self.buffer = vim.current.buffer
|
||||
self.screen_encoding = vim.eval('&fileencoding')
|
||||
|
||||
|
||||
def read(self, timeout=1, set_cursor=True, return_output=False, update_buffer=True):
|
||||
""" Read from console and update Vim buffer. """
|
||||
|
||||
try:
|
||||
stats = self.proc.get_stats()
|
||||
|
||||
if not stats:
|
||||
return
|
||||
|
||||
# disable screen and buffer redraws in fast mode
|
||||
if not CONQUE_FAST_MODE:
|
||||
self.buffer_redraw_ct += 1
|
||||
self.screen_redraw_ct += 1
|
||||
|
||||
update_top = 0
|
||||
update_bottom = 0
|
||||
lines = []
|
||||
|
||||
# full buffer redraw, our favorite!
|
||||
#if self.buffer_redraw_ct == CONQUE_SOLE_BUFFER_REDRAW:
|
||||
# self.buffer_redraw_ct = 0
|
||||
# update_top = 0
|
||||
# update_bottom = stats['top_offset'] + self.lines
|
||||
# (lines, attributes) = self.proc.read(update_top, update_bottom)
|
||||
# if return_output:
|
||||
# output = self.get_new_output(lines, update_top, stats)
|
||||
# if update_buffer:
|
||||
# for i in range(update_top, update_bottom + 1):
|
||||
# if CONQUE_FAST_MODE:
|
||||
# self.plain_text(i, lines[i], None, stats)
|
||||
# else:
|
||||
# self.plain_text(i, lines[i], attributes[i], stats)
|
||||
|
||||
# full screen redraw
|
||||
if stats['cursor_y'] + 1 != self.l or stats['top_offset'] != self.window_top or self.screen_redraw_ct >= CONQUE_SOLE_SCREEN_REDRAW:
|
||||
|
||||
self.screen_redraw_ct = 0
|
||||
update_top = self.window_top
|
||||
update_bottom = max([stats['top_offset'] + self.lines + 1, stats['cursor_y']])
|
||||
(lines, attributes) = self.proc.read(update_top, update_bottom - update_top + 1)
|
||||
if return_output:
|
||||
output = self.get_new_output(lines, update_top, stats)
|
||||
if update_buffer:
|
||||
for i in range(update_top, update_bottom + 1):
|
||||
if CONQUE_FAST_MODE:
|
||||
self.plain_text(i, lines[i - update_top], None, stats)
|
||||
else:
|
||||
self.plain_text(i, lines[i - update_top], attributes[i - update_top], stats)
|
||||
|
||||
|
||||
# single line redraw
|
||||
else:
|
||||
update_top = stats['cursor_y']
|
||||
(lines, attributes) = self.proc.read(update_top, 1)
|
||||
if return_output:
|
||||
output = self.get_new_output(lines, update_top, stats)
|
||||
if update_buffer:
|
||||
if lines[0].rstrip() != u(self.buffer[update_top].rstrip()):
|
||||
if CONQUE_FAST_MODE:
|
||||
self.plain_text(update_top, lines[0], None, stats)
|
||||
else:
|
||||
self.plain_text(update_top, lines[0], attributes[0], stats)
|
||||
|
||||
|
||||
# reset current position
|
||||
self.window_top = stats['top_offset']
|
||||
self.l = stats['cursor_y'] + 1
|
||||
self.c = stats['cursor_x'] + 1
|
||||
|
||||
# reposition cursor if this seems plausible
|
||||
if set_cursor:
|
||||
self.set_cursor(self.l, self.c)
|
||||
|
||||
if return_output:
|
||||
return output
|
||||
|
||||
except:
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def get_new_output(self, lines, update_top, stats):
|
||||
""" Calculate the "new" output from this read. Fake but useful """
|
||||
|
||||
if not (stats['cursor_y'] + 1 > self.l or (stats['cursor_y'] + 1 == self.l and stats['cursor_x'] + 1 > self.c)):
|
||||
return ""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
try:
|
||||
num_to_return = stats['cursor_y'] - self.l + 2
|
||||
|
||||
lines = lines[self.l - update_top - 1:]
|
||||
|
||||
|
||||
new_output = []
|
||||
|
||||
# first line
|
||||
new_output.append(lines[0][self.c - 1:].rstrip())
|
||||
|
||||
# the rest
|
||||
for i in range(1, num_to_return):
|
||||
new_output.append(lines[i].rstrip())
|
||||
|
||||
except:
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
||||
return "\n".join(new_output)
|
||||
|
||||
|
||||
def plain_text(self, line_nr, text, attributes, stats):
|
||||
""" Write plain text to Vim buffer. """
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# handle line offset
|
||||
line_nr += self.offset
|
||||
|
||||
self.l = line_nr + 1
|
||||
|
||||
# remove trailing whitespace
|
||||
text = text.rstrip()
|
||||
|
||||
# if we're using concealed text for color, then s- is weird
|
||||
if self.color_mode == 'conceal':
|
||||
|
||||
text = self.add_conceal_color(text, attributes, stats, line_nr)
|
||||
|
||||
|
||||
# deal with character encoding
|
||||
if CONQUE_PYTHON_VERSION == 2:
|
||||
val = text.encode(self.screen_encoding)
|
||||
else:
|
||||
# XXX / Vim's python3 interface doesn't accept bytes object
|
||||
val = str(text)
|
||||
|
||||
# update vim buffer
|
||||
if len(self.buffer) <= line_nr:
|
||||
self.buffer.append(val)
|
||||
else:
|
||||
self.buffer[line_nr] = val
|
||||
|
||||
if self.enable_colors and not self.color_mode == 'conceal' and line_nr > self.l - CONQUE_MAX_SYNTAX_LINES:
|
||||
relevant = attributes[0:len(text)]
|
||||
if line_nr not in self.attribute_cache or self.attribute_cache[line_nr] != relevant:
|
||||
self.do_color(attributes=relevant, stats=stats)
|
||||
self.attribute_cache[line_nr] = relevant
|
||||
|
||||
|
||||
def add_conceal_color(self, text, attributes, stats, line_nr):
|
||||
""" Add 'conceal' color strings to output text """
|
||||
|
||||
# stop here if coloration is disabled
|
||||
if not self.enable_colors:
|
||||
return text
|
||||
|
||||
# if no colors for this line, clear everything out
|
||||
if len(attributes) == 0 or attributes == u(chr(stats['default_attribute'])) * len(attributes):
|
||||
return text
|
||||
|
||||
new_text = ''
|
||||
self.color_conceals[line_nr] = []
|
||||
|
||||
attribute_chunks = CONQUE_WIN32_REGEX_ATTR.findall(attributes)
|
||||
offset = 0
|
||||
ends = []
|
||||
for attr in attribute_chunks:
|
||||
attr_num = ord(attr[1])
|
||||
ends = []
|
||||
if attr_num != stats['default_attribute']:
|
||||
|
||||
color = self.translate_color(attr_num)
|
||||
|
||||
new_text += chr(27) + 'sf' + color['fg_code'] + ';'
|
||||
ends.append(chr(27) + 'ef' + color['fg_code'] + ';')
|
||||
self.color_conceals[line_nr].append(offset)
|
||||
|
||||
if attr_num > 15:
|
||||
new_text += chr(27) + 'sb' + color['bg_code'] + ';'
|
||||
ends.append(chr(27) + 'eb' + color['bg_code'] + ';')
|
||||
self.color_conceals[line_nr].append(offset)
|
||||
|
||||
new_text += text[offset:offset + len(attr[0])]
|
||||
|
||||
# close color regions
|
||||
ends.reverse()
|
||||
for i in range(0, len(ends)):
|
||||
self.color_conceals[line_nr].append(len(new_text))
|
||||
new_text += ends[i]
|
||||
|
||||
offset += len(attr[0])
|
||||
|
||||
return new_text
|
||||
|
||||
|
||||
def do_color(self, start=0, end=0, attributes='', stats=None):
|
||||
""" Convert Windows console attributes into Vim syntax highlighting """
|
||||
|
||||
# if no colors for this line, clear everything out
|
||||
if len(attributes) == 0 or attributes == u(chr(stats['default_attribute'])) * len(attributes):
|
||||
self.color_changes = {}
|
||||
self.apply_color(1, len(attributes), self.l)
|
||||
return
|
||||
|
||||
attribute_chunks = CONQUE_WIN32_REGEX_ATTR.findall(attributes)
|
||||
offset = 0
|
||||
for attr in attribute_chunks:
|
||||
attr_num = ord(attr[1])
|
||||
if attr_num != stats['default_attribute']:
|
||||
self.color_changes = self.translate_color(attr_num)
|
||||
self.apply_color(offset + 1, offset + len(attr[0]) + 1, self.l)
|
||||
offset += len(attr[0])
|
||||
|
||||
|
||||
def translate_color(self, attr):
|
||||
""" Convert Windows console attributes into RGB colors """
|
||||
|
||||
# check for cached color
|
||||
if attr in self.color_cache:
|
||||
return self.color_cache[attr]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# convert attribute integer to bit string
|
||||
bit_str = bin(attr)
|
||||
bit_str = bit_str.replace('0b', '')
|
||||
|
||||
# slice foreground and background portions of bit string
|
||||
fg = bit_str[-4:].rjust(4, '0')
|
||||
bg = bit_str[-8:-4].rjust(4, '0')
|
||||
|
||||
# ok, first create foreground #rbg
|
||||
red = int(fg[1]) * 204 + int(fg[0]) * int(fg[1]) * 51
|
||||
green = int(fg[2]) * 204 + int(fg[0]) * int(fg[2]) * 51
|
||||
blue = int(fg[3]) * 204 + int(fg[0]) * int(fg[3]) * 51
|
||||
fg_str = "#%02x%02x%02x" % (red, green, blue)
|
||||
fg_code = "%02x%02x%02x" % (red, green, blue)
|
||||
fg_code = fg_code[0] + fg_code[2] + fg_code[4]
|
||||
|
||||
# ok, first create foreground #rbg
|
||||
red = int(bg[1]) * 204 + int(bg[0]) * int(bg[1]) * 51
|
||||
green = int(bg[2]) * 204 + int(bg[0]) * int(bg[2]) * 51
|
||||
blue = int(bg[3]) * 204 + int(bg[0]) * int(bg[3]) * 51
|
||||
bg_str = "#%02x%02x%02x" % (red, green, blue)
|
||||
bg_code = "%02x%02x%02x" % (red, green, blue)
|
||||
bg_code = bg_code[0] + bg_code[2] + bg_code[4]
|
||||
|
||||
# build value for color_changes
|
||||
|
||||
color = {'guifg': fg_str, 'guibg': bg_str}
|
||||
|
||||
if self.color_mode == 'conceal':
|
||||
color['fg_code'] = fg_code
|
||||
color['bg_code'] = bg_code
|
||||
|
||||
self.color_cache[attr] = color
|
||||
|
||||
return color
|
||||
|
||||
|
||||
def write_vk(self, vk_code):
|
||||
""" write virtual key code to shared memory using proprietary escape seq """
|
||||
|
||||
self.proc.write_vk(vk_code)
|
||||
|
||||
|
||||
def update_window_size(self):
|
||||
""" Resize underlying console if Vim buffer size has changed """
|
||||
|
||||
if vim.current.window.width != self.columns or vim.current.window.height != self.lines:
|
||||
|
||||
|
||||
|
||||
# reset all window size attributes to default
|
||||
self.columns = vim.current.window.width
|
||||
self.lines = vim.current.window.height
|
||||
self.working_columns = vim.current.window.width
|
||||
self.working_lines = vim.current.window.height
|
||||
self.bottom = vim.current.window.height
|
||||
|
||||
self.proc.window_resize(vim.current.window.height, vim.current.window.width)
|
||||
|
||||
|
||||
def set_cursor(self, line, column):
|
||||
""" Update cursor position in Vim buffer """
|
||||
|
||||
|
||||
|
||||
# handle offset
|
||||
line += self.offset
|
||||
|
||||
# shift cursor position to handle concealed text
|
||||
if self.enable_colors and self.color_mode == 'conceal':
|
||||
if line - 1 in self.color_conceals:
|
||||
for c in self.color_conceals[line - 1]:
|
||||
if c < column:
|
||||
column += 7
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
|
||||
# figure out line
|
||||
buffer_line = line
|
||||
if buffer_line > len(self.buffer):
|
||||
for l in range(len(self.buffer) - 1, buffer_line):
|
||||
self.buffer.append('')
|
||||
|
||||
# figure out column
|
||||
real_column = column
|
||||
if len(self.buffer[buffer_line - 1]) < real_column:
|
||||
self.buffer[buffer_line - 1] = self.buffer[buffer_line - 1] + ' ' * (real_column - len(self.buffer[buffer_line - 1]))
|
||||
|
||||
# python version is occasionally grumpy
|
||||
try:
|
||||
vim.current.window.cursor = (buffer_line, real_column - 1)
|
||||
except:
|
||||
vim.command('call cursor(' + str(buffer_line) + ', ' + str(real_column) + ')')
|
||||
|
||||
|
||||
def idle(self):
|
||||
""" go into idle mode """
|
||||
|
||||
self.proc.idle()
|
||||
|
||||
|
||||
def resume(self):
|
||||
""" resume from idle mode """
|
||||
|
||||
self.proc.resume()
|
||||
|
||||
|
||||
def close(self):
|
||||
""" end console subprocess """
|
||||
self.proc.close()
|
||||
|
||||
|
||||
def abort(self):
|
||||
""" end subprocess forcefully """
|
||||
self.proc.close()
|
||||
|
||||
|
||||
def get_buffer_line(self, line):
|
||||
""" get buffer line """
|
||||
return line
|
||||
|
||||
|
||||
# vim:foldmethod=marker
|
|
@ -1,183 +0,0 @@
|
|||
# FILE: autoload/conque_term/conque_sole_communicator.py
|
||||
# AUTHOR: Nico Raffo <nicoraffo@gmail.com>
|
||||
# WEBSITE: http://conque.googlecode.com
|
||||
# MODIFIED: 2011-08-12
|
||||
# VERSION: 2.2, for Vim 7.0
|
||||
# LICENSE:
|
||||
# Conque - Vim terminal/console emulator
|
||||
# Copyright (C) 2009-__YEAR__ Nico Raffo
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
ConqueSoleCommunicator
|
||||
|
||||
This script will create a new Windows console and start the requested program
|
||||
inside of it. This process is launched independently from the parent Vim
|
||||
program, so it has no access to the vim module.
|
||||
|
||||
The main loop in this script reads data from the console and syncs it onto
|
||||
blocks of memory shared with the Vim process. In this way the Vim process
|
||||
and this script can communicate with each other.
|
||||
|
||||
"""
|
||||
|
||||
import time
|
||||
import sys
|
||||
|
||||
from conque_globals import *
|
||||
from conque_win32_util import *
|
||||
from conque_sole_subprocess import *
|
||||
from conque_sole_shared_memory import *
|
||||
|
||||
##############################################################
|
||||
# only run if this file was run directly
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# attempt to catch ALL exceptions to fend of zombies
|
||||
try:
|
||||
|
||||
# simple arg validation
|
||||
|
||||
if len(sys.argv) < 5:
|
||||
|
||||
exit()
|
||||
|
||||
# maximum time this thing reads. 0 means no limit. Only for testing.
|
||||
max_loops = 0
|
||||
|
||||
# read interval, in seconds
|
||||
sleep_time = 0.01
|
||||
|
||||
# idle read interval, in seconds
|
||||
idle_sleep_time = 0.10
|
||||
|
||||
# are we idled?
|
||||
is_idle = False
|
||||
|
||||
# mem key
|
||||
mem_key = sys.argv[1]
|
||||
|
||||
# console width
|
||||
console_width = int(sys.argv[2])
|
||||
|
||||
# console height
|
||||
console_height = int(sys.argv[3])
|
||||
|
||||
# code page
|
||||
code_page = int(sys.argv[4])
|
||||
|
||||
# code page
|
||||
fast_mode = int(sys.argv[5])
|
||||
|
||||
# the actual subprocess to run
|
||||
cmd_line = " ".join(sys.argv[6:])
|
||||
|
||||
|
||||
# width and height
|
||||
options = {'LINES': console_height, 'COLUMNS': console_width, 'CODE_PAGE': code_page, 'FAST_MODE': fast_mode}
|
||||
|
||||
|
||||
|
||||
# set initial idle status
|
||||
shm_command = ConqueSoleSharedMemory(CONQUE_SOLE_COMMANDS_SIZE, 'command', mem_key, serialize=True)
|
||||
shm_command.create('write')
|
||||
|
||||
cmd = shm_command.read()
|
||||
if cmd:
|
||||
|
||||
if cmd['cmd'] == 'idle':
|
||||
is_idle = True
|
||||
shm_command.clear()
|
||||
|
||||
|
||||
##############################################################
|
||||
# Create the subprocess
|
||||
|
||||
proc = ConqueSoleSubprocess()
|
||||
res = proc.open(cmd_line, mem_key, options)
|
||||
|
||||
if not res:
|
||||
|
||||
exit()
|
||||
|
||||
##############################################################
|
||||
# main loop!
|
||||
|
||||
loops = 0
|
||||
|
||||
while True:
|
||||
|
||||
# check for idle/resume
|
||||
if is_idle or loops % 25 == 0:
|
||||
|
||||
# check process health
|
||||
if not proc.is_alive():
|
||||
|
||||
proc.close()
|
||||
break
|
||||
|
||||
# check for change in buffer focus
|
||||
cmd = shm_command.read()
|
||||
if cmd:
|
||||
|
||||
if cmd['cmd'] == 'idle':
|
||||
is_idle = True
|
||||
shm_command.clear()
|
||||
|
||||
elif cmd['cmd'] == 'resume':
|
||||
is_idle = False
|
||||
shm_command.clear()
|
||||
|
||||
|
||||
# sleep between loops if moderation is requested
|
||||
if sleep_time > 0:
|
||||
if is_idle:
|
||||
time.sleep(idle_sleep_time)
|
||||
else:
|
||||
time.sleep(sleep_time)
|
||||
|
||||
# write, read, etc
|
||||
proc.write()
|
||||
proc.read()
|
||||
|
||||
# increment loops, and exit if max has been reached
|
||||
loops += 1
|
||||
if max_loops and loops >= max_loops:
|
||||
|
||||
break
|
||||
|
||||
##############################################################
|
||||
# all done!
|
||||
|
||||
|
||||
|
||||
proc.close()
|
||||
|
||||
# if an exception was thrown, croak
|
||||
except:
|
||||
|
||||
proc.close()
|
||||
|
||||
|
||||
# vim:foldmethod=marker
|
|
@ -1,210 +0,0 @@
|
|||
# FILE: autoload/conque_term/conque_sole_shared_memory.py
|
||||
# AUTHOR: Nico Raffo <nicoraffo@gmail.com>
|
||||
# WEBSITE: http://conque.googlecode.com
|
||||
# MODIFIED: 2011-08-12
|
||||
# VERSION: 2.2, for Vim 7.0
|
||||
# LICENSE:
|
||||
# Conque - Vim terminal/console emulator
|
||||
# Copyright (C) 2009-__YEAR__ Nico Raffo
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""
|
||||
Wrapper class for shared memory between Windows python processes
|
||||
|
||||
Adds a small amount of functionality to the standard mmap module.
|
||||
|
||||
"""
|
||||
|
||||
import mmap
|
||||
import sys
|
||||
|
||||
# PYTHON VERSION
|
||||
CONQUE_PYTHON_VERSION = sys.version_info[0]
|
||||
|
||||
if CONQUE_PYTHON_VERSION == 2:
|
||||
import cPickle as pickle
|
||||
else:
|
||||
import pickle
|
||||
|
||||
|
||||
class ConqueSoleSharedMemory():
|
||||
|
||||
# is the data being stored not fixed length
|
||||
fixed_length = False
|
||||
|
||||
# maximum number of bytes per character, for fixed width blocks
|
||||
char_width = 1
|
||||
|
||||
# fill memory with this character when clearing and fixed_length is true
|
||||
FILL_CHAR = None
|
||||
|
||||
# serialize and unserialize data automatically
|
||||
serialize = False
|
||||
|
||||
# size of shared memory, in bytes / chars
|
||||
mem_size = None
|
||||
|
||||
# size of shared memory, in bytes / chars
|
||||
mem_type = None
|
||||
|
||||
# unique key, so multiple console instances are possible
|
||||
mem_key = None
|
||||
|
||||
# mmap instance
|
||||
shm = None
|
||||
|
||||
# character encoding, dammit
|
||||
encoding = 'utf-8'
|
||||
|
||||
# pickle terminator
|
||||
TERMINATOR = None
|
||||
|
||||
|
||||
def __init__(self, mem_size, mem_type, mem_key, fixed_length=False, fill_char=' ', serialize=False, encoding='utf-8'):
|
||||
""" Initialize new shared memory block instance
|
||||
|
||||
Arguments:
|
||||
mem_size -- Memory size in characters, depends on encoding argument to calcuate byte size
|
||||
mem_type -- Label to identify what will be stored
|
||||
mem_key -- Unique, probably random key to identify this block
|
||||
fixed_length -- If set to true, assume the data stored will always fill the memory size
|
||||
fill_char -- Initialize memory block with this character, only really helpful with fixed_length blocks
|
||||
serialize -- Automatically serialize data passed to write. Allows storing non-byte data
|
||||
encoding -- Character encoding to use when storing character data
|
||||
|
||||
"""
|
||||
self.mem_size = mem_size
|
||||
self.mem_type = mem_type
|
||||
self.mem_key = mem_key
|
||||
self.fixed_length = fixed_length
|
||||
self.fill_char = fill_char
|
||||
self.serialize = serialize
|
||||
self.encoding = encoding
|
||||
self.TERMINATOR = str(chr(0)).encode(self.encoding)
|
||||
|
||||
if CONQUE_PYTHON_VERSION == 3:
|
||||
self.FILL_CHAR = fill_char
|
||||
else:
|
||||
self.FILL_CHAR = unicode(fill_char)
|
||||
|
||||
if fixed_length and encoding == 'utf-8':
|
||||
self.char_width = 4
|
||||
|
||||
|
||||
def create(self, access='write'):
|
||||
""" Create a new block of shared memory using the mmap module. """
|
||||
|
||||
if access == 'write':
|
||||
mmap_access = mmap.ACCESS_WRITE
|
||||
else:
|
||||
mmap_access = mmap.ACCESS_READ
|
||||
|
||||
name = "conque_%s_%s" % (self.mem_type, self.mem_key)
|
||||
|
||||
self.shm = mmap.mmap(0, self.mem_size * self.char_width, name, mmap_access)
|
||||
|
||||
if not self.shm:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def read(self, chars=1, start=0):
|
||||
""" Read data from shared memory.
|
||||
|
||||
If this is a fixed length block, read 'chars' characters from memory.
|
||||
Otherwise read up until the TERMINATOR character (null byte).
|
||||
If this memory is serialized, unserialize it automatically.
|
||||
|
||||
"""
|
||||
# go to start position
|
||||
self.shm.seek(start * self.char_width)
|
||||
|
||||
if self.fixed_length:
|
||||
chars = chars * self.char_width
|
||||
else:
|
||||
chars = self.shm.find(self.TERMINATOR)
|
||||
|
||||
if chars == 0:
|
||||
return ''
|
||||
|
||||
shm_str = self.shm.read(chars)
|
||||
|
||||
# return unpickled byte object
|
||||
if self.serialize:
|
||||
return pickle.loads(shm_str)
|
||||
|
||||
# decode byes in python 3
|
||||
if CONQUE_PYTHON_VERSION == 3:
|
||||
return str(shm_str, self.encoding)
|
||||
|
||||
# encoding
|
||||
if self.encoding != 'ascii':
|
||||
shm_str = unicode(shm_str, self.encoding)
|
||||
|
||||
return shm_str
|
||||
|
||||
|
||||
def write(self, text, start=0):
|
||||
""" Write data to memory.
|
||||
|
||||
If memory is fixed length, simply write the 'text' characters at 'start' position.
|
||||
Otherwise write 'text' characters and append a null character.
|
||||
If memory is serializable, do so first.
|
||||
|
||||
"""
|
||||
# simple scenario, let pickle create bytes
|
||||
if self.serialize:
|
||||
if CONQUE_PYTHON_VERSION == 3:
|
||||
tb = pickle.dumps(text, 0)
|
||||
else:
|
||||
tb = pickle.dumps(text, 0).encode(self.encoding)
|
||||
|
||||
else:
|
||||
tb = text.encode(self.encoding, 'replace')
|
||||
|
||||
# write to memory
|
||||
self.shm.seek(start * self.char_width)
|
||||
|
||||
if self.fixed_length:
|
||||
self.shm.write(tb)
|
||||
else:
|
||||
self.shm.write(tb + self.TERMINATOR)
|
||||
|
||||
|
||||
def clear(self, start=0):
|
||||
""" Clear memory block using self.fill_char. """
|
||||
|
||||
self.shm.seek(start)
|
||||
|
||||
if self.fixed_length:
|
||||
self.shm.write(str(self.fill_char * self.mem_size * self.char_width).encode(self.encoding))
|
||||
else:
|
||||
self.shm.write(self.TERMINATOR)
|
||||
|
||||
|
||||
def close(self):
|
||||
""" Close/destroy memory block. """
|
||||
|
||||
self.shm.close()
|
||||
|
||||
|
|
@ -1,762 +0,0 @@
|
|||
# FILE: autoload/conque_term/conque_sole_subprocess.py
|
||||
# AUTHOR: Nico Raffo <nicoraffo@gmail.com>
|
||||
# WEBSITE: http://conque.googlecode.com
|
||||
# MODIFIED: 2011-08-12
|
||||
# VERSION: 2.2, for Vim 7.0
|
||||
# LICENSE:
|
||||
# Conque - Vim terminal/console emulator
|
||||
# Copyright (C) 2009-__YEAR__ Nico Raffo
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
""" ConqueSoleSubprocess
|
||||
|
||||
Creates a new subprocess with it's own (hidden) console window.
|
||||
|
||||
Mirrors console window text onto a block of shared memory (mmap), along with
|
||||
text attribute data. Also handles translation of text input into the format
|
||||
Windows console expects.
|
||||
|
||||
Sample Usage:
|
||||
|
||||
sh = ConqueSoleSubprocess()
|
||||
sh.open("cmd.exe", "unique_str")
|
||||
|
||||
shm_in = ConqueSoleSharedMemory(mem_key = "unique_str", mem_type = "input", ...)
|
||||
shm_out = ConqueSoleSharedMemory(mem_key = "unique_str", mem_type = "output", ...)
|
||||
|
||||
output = shm_out.read(...)
|
||||
shm_in.write("dir\r")
|
||||
output = shm_out.read(...)
|
||||
|
||||
"""
|
||||
|
||||
import time
|
||||
import re
|
||||
import os
|
||||
import ctypes
|
||||
|
||||
from conque_globals import *
|
||||
from conque_win32_util import *
|
||||
from conque_sole_shared_memory import *
|
||||
|
||||
|
||||
class ConqueSoleSubprocess():
|
||||
|
||||
# subprocess handle and pid
|
||||
handle = None
|
||||
pid = None
|
||||
|
||||
# input / output handles
|
||||
stdin = None
|
||||
stdout = None
|
||||
|
||||
# size of console window
|
||||
window_width = 160
|
||||
window_height = 40
|
||||
|
||||
# max lines for the console buffer
|
||||
buffer_width = 160
|
||||
buffer_height = 100
|
||||
|
||||
# keep track of the buffer number at the top of the window
|
||||
top = 0
|
||||
line_offset = 0
|
||||
|
||||
# buffer height is CONQUE_SOLE_BUFFER_LENGTH * output_blocks
|
||||
output_blocks = 1
|
||||
|
||||
# cursor position
|
||||
cursor_line = 0
|
||||
cursor_col = 0
|
||||
|
||||
# console data, array of lines
|
||||
data = []
|
||||
|
||||
# console attribute data, array of array of int
|
||||
attributes = []
|
||||
attribute_cache = {}
|
||||
|
||||
# default attribute
|
||||
default_attribute = 7
|
||||
|
||||
# shared memory objects
|
||||
shm_input = None
|
||||
shm_output = None
|
||||
shm_attributes = None
|
||||
shm_stats = None
|
||||
shm_command = None
|
||||
shm_rescroll = None
|
||||
shm_resize = None
|
||||
|
||||
# are we still a valid process?
|
||||
is_alive = True
|
||||
|
||||
# running in fast mode
|
||||
fast_mode = 0
|
||||
|
||||
# used for periodic execution of screen and memory redrawing
|
||||
screen_redraw_ct = 0
|
||||
mem_redraw_ct = 0
|
||||
|
||||
|
||||
def open(self, cmd, mem_key, options={}):
|
||||
""" Create subproccess running in hidden console window. """
|
||||
|
||||
|
||||
|
||||
self.reset = True
|
||||
|
||||
try:
|
||||
# if we're already attached to a console, then unattach
|
||||
try:
|
||||
ctypes.windll.kernel32.FreeConsole()
|
||||
except:
|
||||
pass
|
||||
|
||||
# set buffer height
|
||||
self.buffer_height = CONQUE_SOLE_BUFFER_LENGTH
|
||||
|
||||
if 'LINES' in options and 'COLUMNS' in options:
|
||||
self.window_width = options['COLUMNS']
|
||||
self.window_height = options['LINES']
|
||||
self.buffer_width = options['COLUMNS']
|
||||
|
||||
# fast mode
|
||||
self.fast_mode = options['FAST_MODE']
|
||||
|
||||
# console window options
|
||||
si = STARTUPINFO()
|
||||
|
||||
# hide window
|
||||
si.dwFlags |= STARTF_USESHOWWINDOW
|
||||
si.wShowWindow = SW_HIDE
|
||||
#si.wShowWindow = SW_MINIMIZE
|
||||
|
||||
# process options
|
||||
flags = NORMAL_PRIORITY_CLASS | CREATE_NEW_PROCESS_GROUP | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE
|
||||
|
||||
# created process info
|
||||
pi = PROCESS_INFORMATION()
|
||||
|
||||
|
||||
|
||||
# create the process!
|
||||
res = ctypes.windll.kernel32.CreateProcessW(None, u(cmd), None, None, 0, flags, None, u('.'), ctypes.byref(si), ctypes.byref(pi))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# process info
|
||||
self.pid = pi.dwProcessId
|
||||
self.handle = pi.hProcess
|
||||
|
||||
|
||||
|
||||
|
||||
# attach ourselves to the new console
|
||||
# console is not immediately available
|
||||
for i in range(10):
|
||||
time.sleep(0.25)
|
||||
try:
|
||||
|
||||
res = ctypes.windll.kernel32.AttachConsole(self.pid)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
break
|
||||
except:
|
||||
|
||||
pass
|
||||
|
||||
# get input / output handles
|
||||
self.stdout = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
|
||||
self.stdin = ctypes.windll.kernel32.GetStdHandle(STD_INPUT_HANDLE)
|
||||
|
||||
# set buffer size
|
||||
size = COORD(self.buffer_width, self.buffer_height)
|
||||
res = ctypes.windll.kernel32.SetConsoleScreenBufferSize(self.stdout, size)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# prev set size call needs to process
|
||||
time.sleep(0.2)
|
||||
|
||||
# set window size
|
||||
self.set_window_size(self.window_width, self.window_height)
|
||||
|
||||
# set utf-8 code page
|
||||
if 'CODE_PAGE' in options and options['CODE_PAGE'] > 0:
|
||||
if ctypes.windll.kernel32.IsValidCodePage(ctypes.c_uint(options['CODE_PAGE'])):
|
||||
|
||||
ctypes.windll.kernel32.SetConsoleCP(ctypes.c_uint(options['CODE_PAGE']))
|
||||
ctypes.windll.kernel32.SetConsoleOutputCP(ctypes.c_uint(options['CODE_PAGE']))
|
||||
|
||||
# init shared memory
|
||||
self.init_shared_memory(mem_key)
|
||||
|
||||
# init read buffers
|
||||
self.tc = ctypes.create_unicode_buffer(self.buffer_width)
|
||||
self.ac = ctypes.create_unicode_buffer(self.buffer_width)
|
||||
|
||||
return True
|
||||
|
||||
except:
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def init_shared_memory(self, mem_key):
|
||||
""" Create shared memory objects. """
|
||||
|
||||
self.shm_input = ConqueSoleSharedMemory(CONQUE_SOLE_INPUT_SIZE, 'input', mem_key)
|
||||
self.shm_input.create('write')
|
||||
self.shm_input.clear()
|
||||
|
||||
self.shm_output = ConqueSoleSharedMemory(self.buffer_height * self.buffer_width, 'output', mem_key, True)
|
||||
self.shm_output.create('write')
|
||||
self.shm_output.clear()
|
||||
|
||||
if not self.fast_mode:
|
||||
buf_info = self.get_buffer_info()
|
||||
self.shm_attributes = ConqueSoleSharedMemory(self.buffer_height * self.buffer_width, 'attributes', mem_key, True, chr(buf_info.wAttributes), encoding='latin-1')
|
||||
self.shm_attributes.create('write')
|
||||
self.shm_attributes.clear()
|
||||
|
||||
self.shm_stats = ConqueSoleSharedMemory(CONQUE_SOLE_STATS_SIZE, 'stats', mem_key, serialize=True)
|
||||
self.shm_stats.create('write')
|
||||
self.shm_stats.clear()
|
||||
|
||||
self.shm_command = ConqueSoleSharedMemory(CONQUE_SOLE_COMMANDS_SIZE, 'command', mem_key, serialize=True)
|
||||
self.shm_command.create('write')
|
||||
self.shm_command.clear()
|
||||
|
||||
self.shm_resize = ConqueSoleSharedMemory(CONQUE_SOLE_RESIZE_SIZE, 'resize', mem_key, serialize=True)
|
||||
self.shm_resize.create('write')
|
||||
self.shm_resize.clear()
|
||||
|
||||
self.shm_rescroll = ConqueSoleSharedMemory(CONQUE_SOLE_RESCROLL_SIZE, 'rescroll', mem_key, serialize=True)
|
||||
self.shm_rescroll.create('write')
|
||||
self.shm_rescroll.clear()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_commands(self):
|
||||
""" Check for and process commands from Vim. """
|
||||
|
||||
cmd = self.shm_command.read()
|
||||
|
||||
if cmd:
|
||||
|
||||
# shut it all down
|
||||
if cmd['cmd'] == 'close':
|
||||
|
||||
# clear command
|
||||
self.shm_command.clear()
|
||||
|
||||
self.close()
|
||||
return
|
||||
|
||||
cmd = self.shm_resize.read()
|
||||
|
||||
if cmd:
|
||||
|
||||
# clear command
|
||||
self.shm_resize.clear()
|
||||
|
||||
# resize console
|
||||
if cmd['cmd'] == 'resize':
|
||||
|
||||
|
||||
|
||||
# only change buffer width if it's larger
|
||||
if cmd['data']['width'] > self.buffer_width:
|
||||
self.buffer_width = cmd['data']['width']
|
||||
|
||||
# always change console width and height
|
||||
self.window_width = cmd['data']['width']
|
||||
self.window_height = cmd['data']['height']
|
||||
|
||||
# reset the console
|
||||
buf_info = self.get_buffer_info()
|
||||
self.reset_console(buf_info, add_block=False)
|
||||
|
||||
|
||||
def read(self):
|
||||
""" Read from windows console and update shared memory blocks. """
|
||||
|
||||
# no point really
|
||||
if self.screen_redraw_ct == 0 and not self.is_alive():
|
||||
stats = {'top_offset': 0, 'default_attribute': 0, 'cursor_x': 0, 'cursor_y': self.cursor_line, 'is_alive': 0}
|
||||
|
||||
self.shm_stats.write(stats)
|
||||
return
|
||||
|
||||
# check for commands
|
||||
self.check_commands()
|
||||
|
||||
# get cursor position
|
||||
buf_info = self.get_buffer_info()
|
||||
curs_line = buf_info.dwCursorPosition.Y
|
||||
curs_col = buf_info.dwCursorPosition.X
|
||||
|
||||
# set update range
|
||||
if curs_line != self.cursor_line or self.top != buf_info.srWindow.Top or self.screen_redraw_ct == CONQUE_SOLE_SCREEN_REDRAW:
|
||||
self.screen_redraw_ct = 0
|
||||
|
||||
read_start = self.top
|
||||
read_end = max([buf_info.srWindow.Bottom + 1, curs_line + 1])
|
||||
else:
|
||||
|
||||
read_start = curs_line
|
||||
read_end = curs_line + 1
|
||||
|
||||
|
||||
|
||||
|
||||
# vars used in for loop
|
||||
coord = COORD(0, 0)
|
||||
chars_read = ctypes.c_int(0)
|
||||
|
||||
# read new data
|
||||
for i in range(read_start, read_end):
|
||||
|
||||
coord.Y = i
|
||||
|
||||
res = ctypes.windll.kernel32.ReadConsoleOutputCharacterW(self.stdout, ctypes.byref(self.tc), self.buffer_width, coord, ctypes.byref(chars_read))
|
||||
if not self.fast_mode:
|
||||
ctypes.windll.kernel32.ReadConsoleOutputAttribute(self.stdout, ctypes.byref(self.ac), self.buffer_width, coord, ctypes.byref(chars_read))
|
||||
|
||||
t = self.tc.value
|
||||
if not self.fast_mode:
|
||||
a = self.ac.value
|
||||
|
||||
# add data
|
||||
if i >= len(self.data):
|
||||
for j in range(len(self.data), i + 1):
|
||||
self.data.append('')
|
||||
if not self.fast_mode:
|
||||
self.attributes.append('')
|
||||
|
||||
self.data[i] = t
|
||||
if not self.fast_mode:
|
||||
self.attributes[i] = a
|
||||
|
||||
|
||||
|
||||
|
||||
#for i in range(0, len(t)):
|
||||
|
||||
|
||||
|
||||
|
||||
# write new output to shared memory
|
||||
try:
|
||||
if self.mem_redraw_ct == CONQUE_SOLE_MEM_REDRAW:
|
||||
self.mem_redraw_ct = 0
|
||||
|
||||
for i in range(0, len(self.data)):
|
||||
self.shm_output.write(text=self.data[i], start=self.buffer_width * i)
|
||||
if not self.fast_mode:
|
||||
self.shm_attributes.write(text=self.attributes[i], start=self.buffer_width * i)
|
||||
else:
|
||||
|
||||
for i in range(read_start, read_end):
|
||||
self.shm_output.write(text=self.data[i], start=self.buffer_width * i)
|
||||
if not self.fast_mode:
|
||||
self.shm_attributes.write(text=self.attributes[i], start=self.buffer_width * i)
|
||||
#self.shm_output.write(text=''.join(self.data[read_start:read_end]), start=read_start * self.buffer_width)
|
||||
#self.shm_attributes.write(text=''.join(self.attributes[read_start:read_end]), start=read_start * self.buffer_width)
|
||||
|
||||
# write cursor position to shared memory
|
||||
stats = {'top_offset': buf_info.srWindow.Top, 'default_attribute': buf_info.wAttributes, 'cursor_x': curs_col, 'cursor_y': curs_line, 'is_alive': 1}
|
||||
self.shm_stats.write(stats)
|
||||
|
||||
# adjust screen position
|
||||
self.top = buf_info.srWindow.Top
|
||||
self.cursor_line = curs_line
|
||||
|
||||
# check for reset
|
||||
if curs_line > buf_info.dwSize.Y - 200:
|
||||
self.reset_console(buf_info)
|
||||
|
||||
except:
|
||||
|
||||
|
||||
|
||||
|
||||
pass
|
||||
|
||||
# increment redraw counters
|
||||
self.screen_redraw_ct += 1
|
||||
self.mem_redraw_ct += 1
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def reset_console(self, buf_info, add_block=True):
|
||||
""" Extend the height of the current console if the cursor postion gets within 200 lines of the current size. """
|
||||
|
||||
# sometimes we just want to change the buffer width,
|
||||
# in which case no need to add another block
|
||||
if add_block:
|
||||
self.output_blocks += 1
|
||||
|
||||
# close down old memory
|
||||
self.shm_output.close()
|
||||
self.shm_output = None
|
||||
|
||||
if not self.fast_mode:
|
||||
self.shm_attributes.close()
|
||||
self.shm_attributes = None
|
||||
|
||||
# new shared memory key
|
||||
mem_key = 'mk' + str(time.time())
|
||||
|
||||
# reallocate memory
|
||||
self.shm_output = ConqueSoleSharedMemory(self.buffer_height * self.buffer_width * self.output_blocks, 'output', mem_key, True)
|
||||
self.shm_output.create('write')
|
||||
self.shm_output.clear()
|
||||
|
||||
# backfill data
|
||||
if len(self.data[0]) < self.buffer_width:
|
||||
for i in range(0, len(self.data)):
|
||||
self.data[i] = self.data[i] + ' ' * (self.buffer_width - len(self.data[i]))
|
||||
self.shm_output.write(''.join(self.data))
|
||||
|
||||
if not self.fast_mode:
|
||||
self.shm_attributes = ConqueSoleSharedMemory(self.buffer_height * self.buffer_width * self.output_blocks, 'attributes', mem_key, True, chr(buf_info.wAttributes), encoding='latin-1')
|
||||
self.shm_attributes.create('write')
|
||||
self.shm_attributes.clear()
|
||||
|
||||
# backfill attributes
|
||||
if len(self.attributes[0]) < self.buffer_width:
|
||||
for i in range(0, len(self.attributes)):
|
||||
self.attributes[i] = self.attributes[i] + chr(buf_info.wAttributes) * (self.buffer_width - len(self.attributes[i]))
|
||||
if not self.fast_mode:
|
||||
self.shm_attributes.write(''.join(self.attributes))
|
||||
|
||||
# notify wrapper of new output block
|
||||
self.shm_rescroll.write({'cmd': 'new_output', 'data': {'blocks': self.output_blocks, 'mem_key': mem_key}})
|
||||
|
||||
# set buffer size
|
||||
size = COORD(X=self.buffer_width, Y=self.buffer_height * self.output_blocks)
|
||||
|
||||
res = ctypes.windll.kernel32.SetConsoleScreenBufferSize(self.stdout, size)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# prev set size call needs to process
|
||||
time.sleep(0.2)
|
||||
|
||||
# set window size
|
||||
self.set_window_size(self.window_width, self.window_height)
|
||||
|
||||
# init read buffers
|
||||
self.tc = ctypes.create_unicode_buffer(self.buffer_width)
|
||||
self.ac = ctypes.create_unicode_buffer(self.buffer_width)
|
||||
|
||||
|
||||
|
||||
def write(self):
|
||||
""" Write text to console.
|
||||
|
||||
This function just parses out special sequences for special key events
|
||||
and passes on the text to the plain or virtual key functions.
|
||||
|
||||
"""
|
||||
# get input from shared mem
|
||||
text = self.shm_input.read()
|
||||
|
||||
# nothing to do here
|
||||
if text == u(''):
|
||||
return
|
||||
|
||||
|
||||
|
||||
# clear input queue
|
||||
self.shm_input.clear()
|
||||
|
||||
# split on VK codes
|
||||
chunks = CONQUE_WIN32_REGEX_VK.split(text)
|
||||
|
||||
# if len() is one then no vks
|
||||
if len(chunks) == 1:
|
||||
self.write_plain(text)
|
||||
return
|
||||
|
||||
|
||||
|
||||
# loop over chunks and delegate
|
||||
for t in chunks:
|
||||
|
||||
if t == '':
|
||||
continue
|
||||
|
||||
if CONQUE_WIN32_REGEX_VK.match(t):
|
||||
|
||||
self.write_vk(t[2:-2])
|
||||
else:
|
||||
self.write_plain(t)
|
||||
|
||||
|
||||
def write_plain(self, text):
|
||||
""" Write simple text to subprocess. """
|
||||
|
||||
li = INPUT_RECORD * len(text)
|
||||
list_input = li()
|
||||
|
||||
for i in range(0, len(text)):
|
||||
|
||||
# create keyboard input
|
||||
ke = KEY_EVENT_RECORD()
|
||||
ke.bKeyDown = ctypes.c_byte(1)
|
||||
ke.wRepeatCount = ctypes.c_short(1)
|
||||
|
||||
cnum = ord(text[i])
|
||||
|
||||
ke.wVirtualKeyCode = ctypes.windll.user32.VkKeyScanW(cnum)
|
||||
ke.wVirtualScanCode = ctypes.c_short(ctypes.windll.user32.MapVirtualKeyW(int(cnum), 0))
|
||||
|
||||
if cnum > 31:
|
||||
ke.uChar.UnicodeChar = uchr(cnum)
|
||||
elif cnum == 3:
|
||||
ctypes.windll.kernel32.GenerateConsoleCtrlEvent(0, self.pid)
|
||||
ke.uChar.UnicodeChar = uchr(cnum)
|
||||
ke.wVirtualKeyCode = ctypes.windll.user32.VkKeyScanW(cnum + 96)
|
||||
ke.dwControlKeyState |= LEFT_CTRL_PRESSED
|
||||
else:
|
||||
ke.uChar.UnicodeChar = uchr(cnum)
|
||||
if cnum in CONQUE_WINDOWS_VK_INV:
|
||||
ke.wVirtualKeyCode = cnum
|
||||
else:
|
||||
ke.wVirtualKeyCode = ctypes.windll.user32.VkKeyScanW(cnum + 96)
|
||||
ke.dwControlKeyState |= LEFT_CTRL_PRESSED
|
||||
|
||||
|
||||
|
||||
|
||||
kc = INPUT_RECORD(KEY_EVENT)
|
||||
kc.Event.KeyEvent = ke
|
||||
list_input[i] = kc
|
||||
|
||||
|
||||
|
||||
# write input array
|
||||
events_written = ctypes.c_int()
|
||||
res = ctypes.windll.kernel32.WriteConsoleInputW(self.stdin, list_input, len(text), ctypes.byref(events_written))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def write_vk(self, vk_code):
|
||||
""" Write special characters to console subprocess. """
|
||||
|
||||
|
||||
|
||||
code = None
|
||||
ctrl_pressed = False
|
||||
|
||||
# this could be made more generic when more attributes
|
||||
# other than ctrl_pressed are available
|
||||
vk_attributes = vk_code.split(';')
|
||||
|
||||
for attr in vk_attributes:
|
||||
if attr == CONQUE_VK_ATTR_CTRL_PRESSED:
|
||||
ctrl_pressed = True
|
||||
else:
|
||||
code = attr
|
||||
|
||||
li = INPUT_RECORD * 1
|
||||
|
||||
# create keyboard input
|
||||
ke = KEY_EVENT_RECORD()
|
||||
ke.uChar.UnicodeChar = uchr(0)
|
||||
ke.wVirtualKeyCode = ctypes.c_short(int(code))
|
||||
ke.wVirtualScanCode = ctypes.c_short(ctypes.windll.user32.MapVirtualKeyW(int(code), 0))
|
||||
ke.bKeyDown = ctypes.c_byte(1)
|
||||
ke.wRepeatCount = ctypes.c_short(1)
|
||||
|
||||
# set enhanced key mode for arrow keys
|
||||
if code in CONQUE_WINDOWS_VK_ENHANCED:
|
||||
|
||||
ke.dwControlKeyState |= ENHANCED_KEY
|
||||
|
||||
if ctrl_pressed:
|
||||
ke.dwControlKeyState |= LEFT_CTRL_PRESSED
|
||||
|
||||
kc = INPUT_RECORD(KEY_EVENT)
|
||||
kc.Event.KeyEvent = ke
|
||||
list_input = li(kc)
|
||||
|
||||
# write input array
|
||||
events_written = ctypes.c_int()
|
||||
res = ctypes.windll.kernel32.WriteConsoleInputW(self.stdin, list_input, 1, ctypes.byref(events_written))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def close(self):
|
||||
""" Close all running subproccesses """
|
||||
|
||||
# record status
|
||||
self.is_alive = False
|
||||
try:
|
||||
stats = {'top_offset': 0, 'default_attribute': 0, 'cursor_x': 0, 'cursor_y': self.cursor_line, 'is_alive': 0}
|
||||
self.shm_stats.write(stats)
|
||||
except:
|
||||
pass
|
||||
|
||||
pid_list = (ctypes.c_int * 10)()
|
||||
num = ctypes.windll.kernel32.GetConsoleProcessList(pid_list, 10)
|
||||
|
||||
|
||||
|
||||
current_pid = os.getpid()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# kill subprocess pids
|
||||
for pid in pid_list[0:num]:
|
||||
if not pid:
|
||||
break
|
||||
|
||||
# kill current pid last
|
||||
if pid == current_pid:
|
||||
continue
|
||||
try:
|
||||
self.close_pid(pid)
|
||||
except:
|
||||
|
||||
pass
|
||||
|
||||
# kill this process
|
||||
try:
|
||||
self.close_pid(current_pid)
|
||||
except:
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def close_pid(self, pid):
|
||||
""" Terminate a single process. """
|
||||
|
||||
|
||||
handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, 0, pid)
|
||||
ctypes.windll.kernel32.TerminateProcess(handle, -1)
|
||||
ctypes.windll.kernel32.CloseHandle(handle)
|
||||
|
||||
|
||||
def is_alive(self):
|
||||
""" Check process health. """
|
||||
|
||||
status = ctypes.windll.kernel32.WaitForSingleObject(self.handle, 1)
|
||||
|
||||
if status == 0:
|
||||
|
||||
self.is_alive = False
|
||||
|
||||
return self.is_alive
|
||||
|
||||
|
||||
def get_screen_text(self):
|
||||
""" Return screen data as string. """
|
||||
|
||||
return "\n".join(self.data)
|
||||
|
||||
|
||||
def set_window_size(self, width, height):
|
||||
""" Change Windows console size. """
|
||||
|
||||
|
||||
|
||||
# get current window size object
|
||||
window_size = SMALL_RECT(0, 0, 0, 0)
|
||||
|
||||
# buffer info has maximum window size data
|
||||
buf_info = self.get_buffer_info()
|
||||
|
||||
|
||||
# set top left corner
|
||||
window_size.Top = 0
|
||||
window_size.Left = 0
|
||||
|
||||
# set bottom right corner
|
||||
if buf_info.dwMaximumWindowSize.X < width:
|
||||
|
||||
window_size.Right = buf_info.dwMaximumWindowSize.X - 1
|
||||
else:
|
||||
window_size.Right = width - 1
|
||||
|
||||
if buf_info.dwMaximumWindowSize.Y < height:
|
||||
|
||||
window_size.Bottom = buf_info.dwMaximumWindowSize.Y - 1
|
||||
else:
|
||||
window_size.Bottom = height - 1
|
||||
|
||||
|
||||
|
||||
# set the window size!
|
||||
res = ctypes.windll.kernel32.SetConsoleWindowInfo(self.stdout, ctypes.c_bool(True), ctypes.byref(window_size))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# reread buffer info to get final console max lines
|
||||
buf_info = self.get_buffer_info()
|
||||
|
||||
self.window_width = buf_info.srWindow.Right + 1
|
||||
self.window_height = buf_info.srWindow.Bottom + 1
|
||||
|
||||
|
||||
def get_buffer_info(self):
|
||||
""" Retrieve commonly-used buffer information. """
|
||||
|
||||
buf_info = CONSOLE_SCREEN_BUFFER_INFO()
|
||||
ctypes.windll.kernel32.GetConsoleScreenBufferInfo(self.stdout, ctypes.byref(buf_info))
|
||||
|
||||
return buf_info
|
||||
|
||||
|
||||
|
|
@ -1,278 +0,0 @@
|
|||
# FILE: autoload/conque_term/conque_sole_wrapper.py
|
||||
# AUTHOR: Nico Raffo <nicoraffo@gmail.com>
|
||||
# WEBSITE: http://conque.googlecode.com
|
||||
# MODIFIED: 2011-08-12
|
||||
# VERSION: 2.2, for Vim 7.0
|
||||
# LICENSE:
|
||||
# Conque - Vim terminal/console emulator
|
||||
# Copyright (C) 2009-__YEAR__ Nico Raffo
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""
|
||||
|
||||
ConqueSoleSubprocessWrapper
|
||||
|
||||
Subprocess wrapper to deal with Windows insanity. Launches console based python,
|
||||
which in turn launches originally requested command. Communicates with cosole
|
||||
python through shared memory objects.
|
||||
|
||||
"""
|
||||
|
||||
import ctypes
|
||||
import time
|
||||
|
||||
|
||||
class ConqueSoleWrapper():
|
||||
|
||||
# unique key used for shared memory block names
|
||||
shm_key = ''
|
||||
|
||||
# process info
|
||||
handle = None
|
||||
pid = None
|
||||
|
||||
# queue input in this bucket
|
||||
bucket = None
|
||||
|
||||
# console size
|
||||
lines = 24
|
||||
columns = 80
|
||||
|
||||
# shared memory objects
|
||||
shm_input = None
|
||||
shm_output = None
|
||||
shm_attributes = None
|
||||
shm_stats = None
|
||||
shm_command = None
|
||||
shm_rescroll = None
|
||||
shm_resize = None
|
||||
|
||||
# console python process
|
||||
proc = None
|
||||
|
||||
|
||||
def open(self, cmd, lines, columns, python_exe='python.exe', communicator_py='conque_sole_communicator.py', options={}):
|
||||
""" Launch python.exe subprocess which will in turn launch the user's program.
|
||||
|
||||
Arguments:
|
||||
cmd -- The user's command to run. E.g. "Powershell.exe" or "C:\Python27\Scripts\ipython.bat"
|
||||
lines, columns -- The size of the console, also the size of the Vim buffer
|
||||
python.exe -- The path to the python executable, typically C:\PythonXX\python.exe
|
||||
communicator_py -- The path to the subprocess controller script in the user's vimfiles directory
|
||||
options -- optional configuration
|
||||
|
||||
"""
|
||||
self.lines = lines
|
||||
self.columns = columns
|
||||
self.bucket = u('')
|
||||
|
||||
# create a shm key
|
||||
self.shm_key = 'mk' + str(time.time())
|
||||
|
||||
# python command
|
||||
cmd_line = '%s "%s" %s %d %d %d %d %s' % (python_exe, communicator_py, self.shm_key, int(self.columns), int(self.lines), int(options['CODE_PAGE']), int(CONQUE_FAST_MODE), cmd)
|
||||
|
||||
|
||||
# console window attributes
|
||||
flags = NORMAL_PRIORITY_CLASS | DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT
|
||||
si = STARTUPINFO()
|
||||
pi = PROCESS_INFORMATION()
|
||||
|
||||
# start the stupid process already
|
||||
try:
|
||||
res = ctypes.windll.kernel32.CreateProcessW(None, u(cmd_line), None, None, 0, flags, None, u('.'), ctypes.byref(si), ctypes.byref(pi))
|
||||
except:
|
||||
|
||||
raise
|
||||
|
||||
# handle
|
||||
self.pid = pi.dwProcessId
|
||||
|
||||
|
||||
|
||||
# init shared memory objects
|
||||
self.init_shared_memory(self.shm_key)
|
||||
|
||||
|
||||
def read(self, start_line, num_lines, timeout=0):
|
||||
""" Read a range of console lines from shared memory.
|
||||
|
||||
Returns a pair of lists containing the console text and console text attributes.
|
||||
|
||||
"""
|
||||
# emulate timeout by sleeping timeout time
|
||||
if timeout > 0:
|
||||
read_timeout = float(timeout) / 1000
|
||||
|
||||
time.sleep(read_timeout)
|
||||
|
||||
output = []
|
||||
attributes = []
|
||||
|
||||
# get output
|
||||
for i in range(start_line, start_line + num_lines + 1):
|
||||
output.append(self.shm_output.read(self.columns, i * self.columns))
|
||||
if not CONQUE_FAST_MODE:
|
||||
attributes.append(self.shm_attributes.read(self.columns, i * self.columns))
|
||||
|
||||
return (output, attributes)
|
||||
|
||||
|
||||
def get_stats(self):
|
||||
""" Return a dictionary with current console cursor and scrolling information. """
|
||||
|
||||
try:
|
||||
rescroll = self.shm_rescroll.read()
|
||||
if rescroll != '' and rescroll != None:
|
||||
|
||||
|
||||
|
||||
self.shm_rescroll.clear()
|
||||
|
||||
# close down old memory
|
||||
self.shm_output.close()
|
||||
self.shm_output = None
|
||||
|
||||
if not CONQUE_FAST_MODE:
|
||||
self.shm_attributes.close()
|
||||
self.shm_attributes = None
|
||||
|
||||
# reallocate memory
|
||||
|
||||
self.shm_output = ConqueSoleSharedMemory(CONQUE_SOLE_BUFFER_LENGTH * self.columns * rescroll['data']['blocks'], 'output', rescroll['data']['mem_key'], True)
|
||||
self.shm_output.create('read')
|
||||
|
||||
if not CONQUE_FAST_MODE:
|
||||
self.shm_attributes = ConqueSoleSharedMemory(CONQUE_SOLE_BUFFER_LENGTH * self.columns * rescroll['data']['blocks'], 'attributes', rescroll['data']['mem_key'], True, encoding='latin-1')
|
||||
self.shm_attributes.create('read')
|
||||
|
||||
stats_str = self.shm_stats.read()
|
||||
if stats_str != '':
|
||||
self.stats = stats_str
|
||||
else:
|
||||
return False
|
||||
except:
|
||||
|
||||
return False
|
||||
|
||||
return self.stats
|
||||
|
||||
|
||||
def is_alive(self):
|
||||
""" Get process status. """
|
||||
|
||||
if not self.shm_stats:
|
||||
return True
|
||||
|
||||
stats_str = self.shm_stats.read()
|
||||
if stats_str:
|
||||
return (stats_str['is_alive'])
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def write(self, text):
|
||||
""" Write input to shared memory. """
|
||||
|
||||
self.bucket += text
|
||||
|
||||
istr = self.shm_input.read()
|
||||
|
||||
if istr == '':
|
||||
|
||||
self.shm_input.write(self.bucket[:500])
|
||||
self.bucket = self.bucket[500:]
|
||||
|
||||
|
||||
def write_vk(self, vk_code):
|
||||
""" Write virtual key code to shared memory using proprietary escape sequences. """
|
||||
|
||||
seq = u("\x1b[") + u(str(vk_code)) + u("VK")
|
||||
self.write(seq)
|
||||
|
||||
|
||||
def idle(self):
|
||||
""" Write idle command to shared memory block, so subprocess controller can hibernate. """
|
||||
|
||||
|
||||
self.shm_command.write({'cmd': 'idle', 'data': {}})
|
||||
|
||||
|
||||
def resume(self):
|
||||
""" Write resume command to shared memory block, so subprocess controller can wake up. """
|
||||
|
||||
self.shm_command.write({'cmd': 'resume', 'data': {}})
|
||||
|
||||
|
||||
def close(self):
|
||||
""" Shut it all down. """
|
||||
|
||||
self.shm_command.write({'cmd': 'close', 'data': {}})
|
||||
time.sleep(0.2)
|
||||
|
||||
|
||||
def window_resize(self, lines, columns):
|
||||
""" Resize console window. """
|
||||
|
||||
self.lines = lines
|
||||
|
||||
# we don't shrink buffer width
|
||||
if columns > self.columns:
|
||||
self.columns = columns
|
||||
|
||||
self.shm_resize.write({'cmd': 'resize', 'data': {'width': columns, 'height': lines}})
|
||||
|
||||
|
||||
def init_shared_memory(self, mem_key):
|
||||
""" Create shared memory objects. """
|
||||
|
||||
self.shm_input = ConqueSoleSharedMemory(CONQUE_SOLE_INPUT_SIZE, 'input', mem_key)
|
||||
self.shm_input.create('write')
|
||||
self.shm_input.clear()
|
||||
|
||||
self.shm_output = ConqueSoleSharedMemory(CONQUE_SOLE_BUFFER_LENGTH * self.columns, 'output', mem_key, True)
|
||||
self.shm_output.create('write')
|
||||
|
||||
if not CONQUE_FAST_MODE:
|
||||
self.shm_attributes = ConqueSoleSharedMemory(CONQUE_SOLE_BUFFER_LENGTH * self.columns, 'attributes', mem_key, True, encoding='latin-1')
|
||||
self.shm_attributes.create('write')
|
||||
|
||||
self.shm_stats = ConqueSoleSharedMemory(CONQUE_SOLE_STATS_SIZE, 'stats', mem_key, serialize=True)
|
||||
self.shm_stats.create('write')
|
||||
self.shm_stats.clear()
|
||||
|
||||
self.shm_command = ConqueSoleSharedMemory(CONQUE_SOLE_COMMANDS_SIZE, 'command', mem_key, serialize=True)
|
||||
self.shm_command.create('write')
|
||||
self.shm_command.clear()
|
||||
|
||||
self.shm_resize = ConqueSoleSharedMemory(CONQUE_SOLE_RESIZE_SIZE, 'resize', mem_key, serialize=True)
|
||||
self.shm_resize.create('write')
|
||||
self.shm_resize.clear()
|
||||
|
||||
self.shm_rescroll = ConqueSoleSharedMemory(CONQUE_SOLE_RESCROLL_SIZE, 'rescroll', mem_key, serialize=True)
|
||||
self.shm_rescroll.create('write')
|
||||
self.shm_rescroll.clear()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# vim:foldmethod=marker
|
|
@ -1,198 +0,0 @@
|
|||
# FILE: autoload/conque_term/conque_subprocess.py
|
||||
# AUTHOR: Nico Raffo <nicoraffo@gmail.com>
|
||||
# WEBSITE: http://conque.googlecode.com
|
||||
# MODIFIED: 2011-08-12
|
||||
# VERSION: 2.2, for Vim 7.0
|
||||
# LICENSE:
|
||||
# Conque - Vim terminal/console emulator
|
||||
# Copyright (C) 2009-__YEAR__ Nico Raffo
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
"""
|
||||
ConqueSubprocess
|
||||
|
||||
Create and interact with a subprocess through a pty.
|
||||
|
||||
Usage:
|
||||
|
||||
p = ConqueSubprocess()
|
||||
p.open('bash', {'TERM':'vt100'})
|
||||
output = p.read()
|
||||
p.write('cd ~/vim' + "\r")
|
||||
p.write('ls -lha' + "\r")
|
||||
output += p.read(timeout = 500)
|
||||
p.close()
|
||||
"""
|
||||
|
||||
import os
|
||||
import signal
|
||||
import pty
|
||||
import tty
|
||||
import select
|
||||
import fcntl
|
||||
import termios
|
||||
import struct
|
||||
import shlex
|
||||
|
||||
|
||||
class ConqueSubprocess:
|
||||
|
||||
# process id
|
||||
pid = 0
|
||||
|
||||
# stdout+stderr file descriptor
|
||||
fd = None
|
||||
|
||||
|
||||
def open(self, command, env={}):
|
||||
""" Create subprocess using forkpty() """
|
||||
|
||||
# parse command
|
||||
command_arr = shlex.split(command)
|
||||
executable = command_arr[0]
|
||||
args = command_arr
|
||||
|
||||
# try to fork a new pty
|
||||
try:
|
||||
self.pid, self.fd = pty.fork()
|
||||
|
||||
except:
|
||||
|
||||
return False
|
||||
|
||||
# child proc, replace with command after altering terminal attributes
|
||||
if self.pid == 0:
|
||||
|
||||
# set requested environment variables
|
||||
for k in env.keys():
|
||||
os.environ[k] = env[k]
|
||||
|
||||
# set tty attributes
|
||||
try:
|
||||
attrs = tty.tcgetattr(1)
|
||||
attrs[0] = attrs[0] ^ tty.IGNBRK
|
||||
attrs[0] = attrs[0] | tty.BRKINT | tty.IXANY | tty.IMAXBEL
|
||||
attrs[2] = attrs[2] | tty.HUPCL
|
||||
attrs[3] = attrs[3] | tty.ICANON | tty.ECHO | tty.ISIG | tty.ECHOKE
|
||||
attrs[6][tty.VMIN] = 1
|
||||
attrs[6][tty.VTIME] = 0
|
||||
tty.tcsetattr(1, tty.TCSANOW, attrs)
|
||||
except:
|
||||
|
||||
pass
|
||||
|
||||
# replace this process with the subprocess
|
||||
os.execvp(executable, args)
|
||||
|
||||
# else master, do nothing
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
def read(self, timeout=1):
|
||||
""" Read from subprocess and return new output """
|
||||
|
||||
output = ''
|
||||
read_timeout = float(timeout) / 1000
|
||||
read_ct = 0
|
||||
|
||||
try:
|
||||
# read from fd until no more output
|
||||
while 1:
|
||||
s_read, s_write, s_error = select.select([self.fd], [], [], read_timeout)
|
||||
|
||||
lines = ''
|
||||
for s_fd in s_read:
|
||||
try:
|
||||
# increase read buffer so huge reads don't slow down
|
||||
if read_ct < 10:
|
||||
lines = os.read(self.fd, 32)
|
||||
elif read_ct < 50:
|
||||
lines = os.read(self.fd, 512)
|
||||
else:
|
||||
lines = os.read(self.fd, 2048)
|
||||
read_ct += 1
|
||||
except:
|
||||
pass
|
||||
output = output + lines.decode('utf-8')
|
||||
|
||||
if lines == '' or read_ct > 100:
|
||||
break
|
||||
except:
|
||||
|
||||
pass
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def write(self, input):
|
||||
""" Write new input to subprocess """
|
||||
|
||||
try:
|
||||
if CONQUE_PYTHON_VERSION == 2:
|
||||
os.write(self.fd, input.encode('utf-8', 'ignore'))
|
||||
else:
|
||||
os.write(self.fd, bytes(input, 'utf-8'))
|
||||
except:
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def signal(self, signum):
|
||||
""" signal process """
|
||||
|
||||
try:
|
||||
os.kill(self.pid, signum)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def close(self):
|
||||
""" close process with sigterm signal """
|
||||
|
||||
self.signal(15)
|
||||
|
||||
|
||||
def is_alive(self):
|
||||
""" get process status """
|
||||
|
||||
p_status = True
|
||||
try:
|
||||
if os.waitpid(self.pid, os.WNOHANG)[0]:
|
||||
p_status = False
|
||||
except:
|
||||
p_status = False
|
||||
|
||||
return p_status
|
||||
|
||||
|
||||
def window_resize(self, lines, columns):
|
||||
""" update window size in kernel, then send SIGWINCH to fg process """
|
||||
|
||||
try:
|
||||
fcntl.ioctl(self.fd, termios.TIOCSWINSZ, struct.pack("HHHH", lines, columns, 0, 0))
|
||||
os.kill(self.pid, signal.SIGWINCH)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# vim:foldmethod=marker
|
|
@ -1,448 +0,0 @@
|
|||
# FILE: autoload/conque_term/conque_win32_util.py
|
||||
# AUTHOR: Nico Raffo <nicoraffo@gmail.com>
|
||||
# WEBSITE: http://conque.googlecode.com
|
||||
# MODIFIED: 2011-08-12
|
||||
# VERSION: 2.2, for Vim 7.0
|
||||
# LICENSE:
|
||||
# Conque - Vim terminal/console emulator
|
||||
# Copyright (C) 2009-__YEAR__ Nico Raffo
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
""" Python constants and structures used for ctypes interaction. """
|
||||
|
||||
from ctypes import *
|
||||
|
||||
# Constants
|
||||
|
||||
# create process flag constants
|
||||
|
||||
CREATE_BREAKAWAY_FROM_JOB = 0x01000000
|
||||
CREATE_DEFAULT_ERROR_MODE = 0x04000000
|
||||
CREATE_NEW_CONSOLE = 0x00000010
|
||||
CREATE_NEW_PROCESS_GROUP = 0x00000200
|
||||
CREATE_NO_WINDOW = 0x08000000
|
||||
CREATE_PROTECTED_PROCESS = 0x00040000
|
||||
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000
|
||||
CREATE_SEPARATE_WOW_VDM = 0x00000800
|
||||
CREATE_SHARED_WOW_VDM = 0x00001000
|
||||
CREATE_SUSPENDED = 0x00000004
|
||||
CREATE_UNICODE_ENVIRONMENT = 0x00000400
|
||||
DEBUG_ONLY_THIS_PROCESS = 0x00000002
|
||||
DEBUG_PROCESS = 0x00000001
|
||||
DETACHED_PROCESS = 0x00000008
|
||||
EXTENDED_STARTUPINFO_PRESENT = 0x00080000
|
||||
INHERIT_PARENT_AFFINITY = 0x00010000
|
||||
|
||||
|
||||
# process priority constants
|
||||
|
||||
ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000
|
||||
BELOW_NORMAL_PRIORITY_CLASS = 0x00004000
|
||||
HIGH_PRIORITY_CLASS = 0x00000080
|
||||
IDLE_PRIORITY_CLASS = 0x00000040
|
||||
NORMAL_PRIORITY_CLASS = 0x00000020
|
||||
REALTIME_PRIORITY_CLASS = 0x00000100
|
||||
|
||||
|
||||
# startup info constants
|
||||
|
||||
STARTF_FORCEONFEEDBACK = 0x00000040
|
||||
STARTF_FORCEOFFFEEDBACK = 0x00000080
|
||||
STARTF_PREVENTPINNING = 0x00002000
|
||||
STARTF_RUNFULLSCREEN = 0x00000020
|
||||
STARTF_TITLEISAPPID = 0x00001000
|
||||
STARTF_TITLEISLINKNAME = 0x00000800
|
||||
STARTF_USECOUNTCHARS = 0x00000008
|
||||
STARTF_USEFILLATTRIBUTE = 0x00000010
|
||||
STARTF_USEHOTKEY = 0x00000200
|
||||
STARTF_USEPOSITION = 0x00000004
|
||||
STARTF_USESHOWWINDOW = 0x00000001
|
||||
STARTF_USESIZE = 0x00000002
|
||||
STARTF_USESTDHANDLES = 0x00000100
|
||||
|
||||
|
||||
# show window constants
|
||||
|
||||
SW_FORCEMINIMIZE = 11
|
||||
SW_HIDE = 0
|
||||
SW_MAXIMIZE = 3
|
||||
SW_MINIMIZE = 6
|
||||
SW_RESTORE = 9
|
||||
SW_SHOW = 5
|
||||
SW_SHOWDEFAULT = 10
|
||||
SW_SHOWMAXIMIZED = 3
|
||||
SW_SHOWMINIMIZED = 2
|
||||
SW_SHOWMINNOACTIVE = 7
|
||||
SW_SHOWNA = 8
|
||||
SW_SHOWNOACTIVATE = 4
|
||||
SW_SHOWNORMAL = 1
|
||||
|
||||
|
||||
# input event types
|
||||
|
||||
FOCUS_EVENT = 0x0010
|
||||
KEY_EVENT = 0x0001
|
||||
MENU_EVENT = 0x0008
|
||||
MOUSE_EVENT = 0x0002
|
||||
WINDOW_BUFFER_SIZE_EVENT = 0x0004
|
||||
|
||||
|
||||
# key event modifiers
|
||||
|
||||
CAPSLOCK_ON = 0x0080
|
||||
ENHANCED_KEY = 0x0100
|
||||
LEFT_ALT_PRESSED = 0x0002
|
||||
LEFT_CTRL_PRESSED = 0x0008
|
||||
NUMLOCK_ON = 0x0020
|
||||
RIGHT_ALT_PRESSED = 0x0001
|
||||
RIGHT_CTRL_PRESSED = 0x0004
|
||||
SCROLLLOCK_ON = 0x0040
|
||||
SHIFT_PRESSED = 0x0010
|
||||
|
||||
|
||||
# process access
|
||||
|
||||
PROCESS_CREATE_PROCESS = 0x0080
|
||||
PROCESS_CREATE_THREAD = 0x0002
|
||||
PROCESS_DUP_HANDLE = 0x0040
|
||||
PROCESS_QUERY_INFORMATION = 0x0400
|
||||
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
|
||||
PROCESS_SET_INFORMATION = 0x0200
|
||||
PROCESS_SET_QUOTA = 0x0100
|
||||
PROCESS_SUSPEND_RESUME = 0x0800
|
||||
PROCESS_TERMINATE = 0x0001
|
||||
PROCESS_VM_OPERATION = 0x0008
|
||||
PROCESS_VM_READ = 0x0010
|
||||
PROCESS_VM_WRITE = 0x0020
|
||||
|
||||
|
||||
# input / output handles
|
||||
|
||||
STD_INPUT_HANDLE = c_ulong(-10)
|
||||
STD_OUTPUT_HANDLE = c_ulong(-11)
|
||||
STD_ERROR_HANDLE = c_ulong(-12)
|
||||
|
||||
|
||||
CONQUE_WINDOWS_VK = {
|
||||
'VK_LBUTTON': 0x0001,
|
||||
'VK_RBUTTON': 0x0002,
|
||||
'VK_CANCEL': 0x0003,
|
||||
'VK_BACK': 0x0008,
|
||||
'VK_TAB': 0x0009,
|
||||
'VK_CLEAR': 0x000C,
|
||||
'VK_RETURN': 0x0D,
|
||||
'VK_SHIFT': 0x10,
|
||||
'VK_CONTROL': 0x11,
|
||||
'VK_MENU': 0x12,
|
||||
'VK_PAUSE': 0x0013,
|
||||
'VK_CAPITAL': 0x0014,
|
||||
'VK_ESCAPE': 0x001B,
|
||||
'VK_SPACE': 0x0020,
|
||||
'VK_PRIOR': 0x0021,
|
||||
'VK_NEXT': 0x0022,
|
||||
'VK_END': 0x0023,
|
||||
'VK_HOME': 0x0024,
|
||||
'VK_LEFT': 0x0025,
|
||||
'VK_UP': 0x0026,
|
||||
'VK_RIGHT': 0x0027,
|
||||
'VK_DOWN': 0x0028,
|
||||
'VK_SELECT': 0x0029,
|
||||
'VK_PRINT': 0x002A,
|
||||
'VK_EXECUTE': 0x002B,
|
||||
'VK_SNAPSHOT': 0x002C,
|
||||
'VK_INSERT': 0x002D,
|
||||
'VK_DELETE': 0x002E,
|
||||
'VK_HELP': 0x002F,
|
||||
'VK_0': 0x0030,
|
||||
'VK_1': 0x0031,
|
||||
'VK_2': 0x0032,
|
||||
'VK_3': 0x0033,
|
||||
'VK_4': 0x0034,
|
||||
'VK_5': 0x0035,
|
||||
'VK_6': 0x0036,
|
||||
'VK_7': 0x0037,
|
||||
'VK_8': 0x0038,
|
||||
'VK_9': 0x0039,
|
||||
'VK_A': 0x0041,
|
||||
'VK_B': 0x0042,
|
||||
'VK_C': 0x0043,
|
||||
'VK_D': 0x0044,
|
||||
'VK_E': 0x0045,
|
||||
'VK_F': 0x0046,
|
||||
'VK_G': 0x0047,
|
||||
'VK_H': 0x0048,
|
||||
'VK_I': 0x0049,
|
||||
'VK_J': 0x004A,
|
||||
'VK_K': 0x004B,
|
||||
'VK_L': 0x004C,
|
||||
'VK_M': 0x004D,
|
||||
'VK_N': 0x004E,
|
||||
'VK_O': 0x004F,
|
||||
'VK_P': 0x0050,
|
||||
'VK_Q': 0x0051,
|
||||
'VK_R': 0x0052,
|
||||
'VK_S': 0x0053,
|
||||
'VK_T': 0x0054,
|
||||
'VK_U': 0x0055,
|
||||
'VK_V': 0x0056,
|
||||
'VK_W': 0x0057,
|
||||
'VK_X': 0x0058,
|
||||
'VK_Y': 0x0059,
|
||||
'VK_Z': 0x005A,
|
||||
'VK_LWIN': 0x005B,
|
||||
'VK_RWIN': 0x005C,
|
||||
'VK_APPS': 0x005D,
|
||||
'VK_SLEEP': 0x005F,
|
||||
'VK_NUMPAD0': 0x0060,
|
||||
'VK_NUMPAD1': 0x0061,
|
||||
'VK_NUMPAD2': 0x0062,
|
||||
'VK_NUMPAD3': 0x0063,
|
||||
'VK_NUMPAD4': 0x0064,
|
||||
'VK_NUMPAD5': 0x0065,
|
||||
'VK_NUMPAD6': 0x0066,
|
||||
'VK_NUMPAD7': 0x0067,
|
||||
'VK_NUMPAD8': 0x0068,
|
||||
'VK_MULTIPLY': 0x006A,
|
||||
'VK_ADD': 0x006B,
|
||||
'VK_SEPARATOR': 0x006C,
|
||||
'VK_SUBTRACT': 0x006D,
|
||||
'VK_DECIMAL': 0x006E,
|
||||
'VK_DIVIDE': 0x006F,
|
||||
'VK_F1': 0x0070,
|
||||
'VK_F2': 0x0071,
|
||||
'VK_F3': 0x0072,
|
||||
'VK_F4': 0x0073,
|
||||
'VK_F5': 0x0074,
|
||||
'VK_F6': 0x0075,
|
||||
'VK_F7': 0x0076,
|
||||
'VK_F8': 0x0077,
|
||||
'VK_F9': 0x0078,
|
||||
'VK_F10': 0x0079,
|
||||
'VK_F11': 0x007A,
|
||||
'VK_F12': 0x007B,
|
||||
'VK_F13': 0x007C,
|
||||
'VK_F14': 0x007D,
|
||||
'VK_F15': 0x007E,
|
||||
'VK_F16': 0x007F,
|
||||
'VK_F17': 0x0080,
|
||||
'VK_F18': 0x0081,
|
||||
'VK_F19': 0x0082,
|
||||
'VK_F20': 0x0083,
|
||||
'VK_F21': 0x0084,
|
||||
'VK_F22': 0x0085,
|
||||
'VK_F23': 0x0086,
|
||||
'VK_F24': 0x0087,
|
||||
'VK_NUMLOCK': 0x0090,
|
||||
'VK_SCROLL': 0x0091,
|
||||
'VK_LSHIFT': 0x00A0,
|
||||
'VK_RSHIFT': 0x00A1,
|
||||
'VK_LCONTROL': 0x00A2,
|
||||
'VK_RCONTROL': 0x00A3,
|
||||
'VK_LMENU': 0x00A4,
|
||||
'VK_RMENU': 0x00A5
|
||||
}
|
||||
|
||||
CONQUE_WINDOWS_VK_INV = dict([v, k] for k, v in CONQUE_WINDOWS_VK.items())
|
||||
|
||||
CONQUE_WINDOWS_VK_ENHANCED = {
|
||||
str(int(CONQUE_WINDOWS_VK['VK_UP'])): 1,
|
||||
str(int(CONQUE_WINDOWS_VK['VK_DOWN'])): 1,
|
||||
str(int(CONQUE_WINDOWS_VK['VK_LEFT'])): 1,
|
||||
str(int(CONQUE_WINDOWS_VK['VK_RIGHT'])): 1,
|
||||
str(int(CONQUE_WINDOWS_VK['VK_HOME'])): 1,
|
||||
str(int(CONQUE_WINDOWS_VK['VK_END'])): 1
|
||||
}
|
||||
|
||||
|
||||
# structures used for CreateProcess
|
||||
|
||||
# Odd types
|
||||
|
||||
LPBYTE = POINTER(c_ubyte)
|
||||
LPTSTR = POINTER(c_char)
|
||||
|
||||
|
||||
class STARTUPINFO(Structure):
|
||||
_fields_ = [("cb", c_ulong),
|
||||
("lpReserved", LPTSTR),
|
||||
("lpDesktop", LPTSTR),
|
||||
("lpTitle", LPTSTR),
|
||||
("dwX", c_ulong),
|
||||
("dwY", c_ulong),
|
||||
("dwXSize", c_ulong),
|
||||
("dwYSize", c_ulong),
|
||||
("dwXCountChars", c_ulong),
|
||||
("dwYCountChars", c_ulong),
|
||||
("dwFillAttribute", c_ulong),
|
||||
("dwFlags", c_ulong),
|
||||
("wShowWindow", c_short),
|
||||
("cbReserved2", c_short),
|
||||
("lpReserved2", LPBYTE),
|
||||
("hStdInput", c_void_p),
|
||||
("hStdOutput", c_void_p),
|
||||
("hStdError", c_void_p),]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class PROCESS_INFORMATION(Structure):
|
||||
_fields_ = [("hProcess", c_void_p),
|
||||
("hThread", c_void_p),
|
||||
("dwProcessId", c_ulong),
|
||||
("dwThreadId", c_ulong),]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class MEMORY_BASIC_INFORMATION(Structure):
|
||||
_fields_ = [("BaseAddress", c_void_p),
|
||||
("AllocationBase", c_void_p),
|
||||
("AllocationProtect", c_ulong),
|
||||
("RegionSize", c_ulong),
|
||||
("State", c_ulong),
|
||||
("Protect", c_ulong),
|
||||
("Type", c_ulong),]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class SECURITY_ATTRIBUTES(Structure):
|
||||
_fields_ = [("Length", c_ulong),
|
||||
("SecDescriptor", c_void_p),
|
||||
("InheritHandle", c_bool)]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class COORD(Structure):
|
||||
_fields_ = [("X", c_short),
|
||||
("Y", c_short)]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class SMALL_RECT(Structure):
|
||||
_fields_ = [("Left", c_short),
|
||||
("Top", c_short),
|
||||
("Right", c_short),
|
||||
("Bottom", c_short)]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class CONSOLE_SCREEN_BUFFER_INFO(Structure):
|
||||
_fields_ = [("dwSize", COORD),
|
||||
("dwCursorPosition", COORD),
|
||||
("wAttributes", c_short),
|
||||
("srWindow", SMALL_RECT),
|
||||
("dwMaximumWindowSize", COORD)]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class CHAR_UNION(Union):
|
||||
_fields_ = [("UnicodeChar", c_wchar),
|
||||
("AsciiChar", c_char)]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class CHAR_INFO(Structure):
|
||||
_fields_ = [("Char", CHAR_UNION),
|
||||
("Attributes", c_short)]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class KEY_EVENT_RECORD(Structure):
|
||||
_fields_ = [("bKeyDown", c_byte),
|
||||
("pad2", c_byte),
|
||||
('pad1', c_short),
|
||||
("wRepeatCount", c_short),
|
||||
("wVirtualKeyCode", c_short),
|
||||
("wVirtualScanCode", c_short),
|
||||
("uChar", CHAR_UNION),
|
||||
("dwControlKeyState", c_int)]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class MOUSE_EVENT_RECORD(Structure):
|
||||
_fields_ = [("dwMousePosition", COORD),
|
||||
("dwButtonState", c_int),
|
||||
("dwControlKeyState", c_int),
|
||||
("dwEventFlags", c_int)]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class WINDOW_BUFFER_SIZE_RECORD(Structure):
|
||||
_fields_ = [("dwSize", COORD)]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class MENU_EVENT_RECORD(Structure):
|
||||
_fields_ = [("dwCommandId", c_uint)]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class FOCUS_EVENT_RECORD(Structure):
|
||||
_fields_ = [("bSetFocus", c_byte)]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class INPUT_UNION(Union):
|
||||
_fields_ = [("KeyEvent", KEY_EVENT_RECORD),
|
||||
("MouseEvent", MOUSE_EVENT_RECORD),
|
||||
("WindowBufferSizeEvent", WINDOW_BUFFER_SIZE_RECORD),
|
||||
("MenuEvent", MENU_EVENT_RECORD),
|
||||
("FocusEvent", FOCUS_EVENT_RECORD)]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
||||
class INPUT_RECORD(Structure):
|
||||
_fields_ = [("EventType", c_short),
|
||||
("Event", INPUT_UNION)]
|
||||
|
||||
def to_str(self):
|
||||
return ''
|
||||
|
||||
|
|
@ -1,646 +0,0 @@
|
|||
*ConqueTerm* Plugin to run a shell inside a Vim buffer
|
||||
|
||||
The ConqueTerm plugin will turn a Vim buffer into a terminal emulator, allowing
|
||||
you to run and interact with a shell or shell application inside the buffer.
|
||||
|
||||
1. Installation |conque-term-setup|
|
||||
1.1 Requirements for Unix |conque-term-requirements|
|
||||
1.2 Requirements for Windows |conque-term-windows|
|
||||
1.3 Installation |conque-term-installation|
|
||||
2. Usage |conque-term-usage|
|
||||
2.1 General Usage |conque-term-gen-usage|
|
||||
2.2 Special keys |conque-term-special-keys|
|
||||
2.2.1 Send text to Conque |conque-term-send|
|
||||
2.2.2 Toggle terminal input mode |conque-term-input-mode|
|
||||
2.2.3 Sending the <Esc> key press |conque-term-esc|
|
||||
3. Configuration |conque-term-options|
|
||||
3.1 General |conque-config-general|
|
||||
3.1.1 Python version |ConqueTerm_PyVersion|
|
||||
3.1.2 Fast mode |ConqueTerm_FastMode|
|
||||
3.1.3 Color support |ConqueTerm_Color|
|
||||
3.1.4 Session Support |ConqueTerm_SessionSupport|
|
||||
3.1.5 Keep updating terminal buffer |ConqueTerm_ReadUnfocused|
|
||||
3.1.6 Insert mode when entering buffer |ConqueTerm_InsertOnEnter|
|
||||
3.1.7 Close buffer when program exits |ConqueTerm_CloseOnEnd|
|
||||
3.1.8 Hide start messages |ConqueTerm_StartMessages|
|
||||
3.1.9 Regex for highlighting your prompt |ConqueTerm_PromptRegex|
|
||||
3.1.10 Syntax type |ConqueTerm_Syntax|
|
||||
3.2 Keyboard |conque-config-keyboard|
|
||||
3.2.1 The <Esc> key |ConqueTerm_EscKey|
|
||||
3.2.2 Toggle terminal input mode |ConqueTerm_ToggleKey|
|
||||
3.2.3 Enable <C-w> in insert mode |ConqueTerm_CWInsert|
|
||||
3.2.4 Execute current file in Conque |ConqueTerm_ExecFileKey|
|
||||
3.2.5 Send current file contents to Conque|ConqueTerm_SendFileKey|
|
||||
3.2.6 Send selected text to Conque |ConqueTerm_SendVisKey|
|
||||
3.2.7 Function Keys |ConqueTerm_SendFunctionKeys|
|
||||
3.3 Unix |conque-config-unix|
|
||||
3.3.1 Choose your terminal type |ConqueTerm_TERM|
|
||||
3.4 Windows |conque-config-windows|
|
||||
3.4.1 Python executable |ConqueTerm_PyExe|
|
||||
3.4.2 Windows character code page |ConqueTerm_CodePage|
|
||||
3.4.3 Terminal color method |ConqueTerm_ColorMode|
|
||||
4. VimScript API |conque-term-api|
|
||||
4.1 conque_term#open() |conque-term-open|
|
||||
4.2 conque_term#subprocess() |conque-term-subprocess|
|
||||
4.3 conque_term#get_instance() |conque-term-get-instance|
|
||||
4.4 CONQUE_OBJECT.write() |conque-term-write|
|
||||
4.5 CONQUE_OBJECT.writeln() |conque-term-writeln|
|
||||
4.6 CONQUE_OBJECT.read() |conque-term-read|
|
||||
4.7 CONQUE_OBJECT.set_callback() |conque-term-set-callback|
|
||||
4.8 CONQUE_OBJECT.close() |conque-term-close|
|
||||
4.9 Registering functions |conque-term-events|
|
||||
5. Misc |conque-term-misc|
|
||||
5.1 Known bugs |conque-term-bugs|
|
||||
5.2 Contribute |conque-term-contribute|
|
||||
5.3 Feedback |conque-term-feedback|
|
||||
|
||||
==============================================================================
|
||||
|
||||
1. Installation *conque-term-setup*
|
||||
|
||||
Conque is designed for both Unix and Windows operating systems, however the
|
||||
requirements are slightly different. Please check section below corresponding
|
||||
to your installed OS.
|
||||
|
||||
1.1 Requirements for Unix *conque-term-requirements*
|
||||
|
||||
* [G]Vim 7.0+ with +python and/or +python3
|
||||
* Python 2.3+ and/or 3.x
|
||||
* Unix-like OS: Linux, OS X, Solaris, Cygwin, etc
|
||||
|
||||
The most common stumbling block is getting a version of Vim which has the
|
||||
python interface enabled. Most all software package managers will have a copy
|
||||
of Vim with Python support, so that is often the easiest way to get it. If
|
||||
you're compiling Vim from source, be sure to use the --enable-pythoninterp
|
||||
option, or --enable-python3interp for Python 3. On OS X the best option is
|
||||
MacVim, which installs with Python support by default.
|
||||
|
||||
1.2 Requirements for Windows *conque-term-windows*
|
||||
|
||||
* [G]Vim 7.3 with +python and/or +python3
|
||||
* Python 2.7 and/or 3.1
|
||||
* Modern Windows OS (XP or later)
|
||||
|
||||
Conque only officially supports the latest GVim 7.3 Windows installer
|
||||
available at www.vim.org. If you are currently using Vim 7.2 or earlier you
|
||||
will need to upgrade to 7.3 for Windows support. The Windows installer already
|
||||
has the +python/+python3 interface built in.
|
||||
|
||||
The official 7.3 release of Vim for Windows only works with Python versions
|
||||
2.7 and/or 3.1. You can download and install Python from their website
|
||||
http://www.python.org/download
|
||||
|
||||
If you are compiling Vim + Python from source on Windows, the requirements
|
||||
become only Vim 7.3+ and Python 2.7+.
|
||||
|
||||
|
||||
1.3 Installation *conque-term-installation*
|
||||
|
||||
Download the latest vimball from http://conque.googlecode.com
|
||||
|
||||
Open the .vba file with Vim and run the following commands:
|
||||
>
|
||||
:so %
|
||||
:q
|
||||
<
|
||||
That's it! The :ConqueTerm command will be available the next time you start
|
||||
Vim. You can delete the .vba file when you've verified Conque was successfully
|
||||
installed.
|
||||
|
||||
==============================================================================
|
||||
|
||||
2. Usage *conque-term-usage*
|
||||
|
||||
2.1 General Usage *conque-term-gen-usage*
|
||||
|
||||
Type :ConqueTerm <command> to launch an application in the current buffer. Eg:
|
||||
>
|
||||
:ConqueTerm bash
|
||||
:ConqueTerm mysql -h localhost -u joe_lunchbox Menu
|
||||
:ConqueTerm Powershell.exe
|
||||
<
|
||||
Use :ConqueTermSplit or :ConqueTermVSplit to open Conque in a new horizontal
|
||||
or vertical buffer. Use :ConqueTermTab to open Conque in a new tab.
|
||||
|
||||
In insert mode you can interact with the shell as you would expect in a
|
||||
normal terminal. All key presses will be sent to the terminal, including
|
||||
control characters. See |conque-term-special-keys| for more information,
|
||||
particularly regarding the <Esc> key.
|
||||
|
||||
In normal mode you can use Vim commands to browse your terminal output and
|
||||
scroll back through the history. Most all Vim functionality will work, such
|
||||
as searching, yanking or highlighting text.
|
||||
|
||||
|
||||
2.2 Special keys *conque-term-special-keys*
|
||||
|
||||
There are several keys which can be configured to have special behavior with
|
||||
Conque.
|
||||
|
||||
2.2.1 Send text to Conque *conque-term-send*
|
||||
|
||||
Conque gives you three different commands to send text from a different
|
||||
buffer, probably a source code file, to the Conque terminal buffer. All three
|
||||
are configurable to use your choice of key combinations.
|
||||
|
||||
To send a visually selected range of text to an existing terminal buffer,
|
||||
press the <F9> key.
|
||||
|
||||
To send the entire contents of the file you are editing to an existing
|
||||
terminal buffer, press the <F10> key.
|
||||
|
||||
Finally, to execute the current file in a new terminal buffer press the <F11>
|
||||
key. This will split the screen with a new Conque buffer. The file you are
|
||||
editing must be executable for this command to work.
|
||||
|
||||
See |conque-term-options| for information about configuring these commands.
|
||||
|
||||
2.2.2 Toggle terminal input mode *conque-term-input-mode*
|
||||
|
||||
If you want to use insert mode to edit the terminal screen, press <F8>. You
|
||||
will now be able to edit the terminal output freely without your cursor
|
||||
jumping the the active prompt line. This may be useful if you want to reformat
|
||||
terminal output for readability.
|
||||
|
||||
While the terminal is paused new output will not be displayed on the screen
|
||||
until you press <F8> again to resume.
|
||||
|
||||
You can configure Conque to use a different key with the |ConqueTerm_ToggleKey|
|
||||
option.
|
||||
|
||||
2.2.3 Sending the <Esc> key press *conque-term-esc*
|
||||
|
||||
By default if you press the <Esc> key in a Conque buffer you will leave insert
|
||||
mode. But what if you want the <Esc> character to be sent to your terminal?
|
||||
There are two options. By default, pressing <Esc> twice will send one <Esc>
|
||||
character to the terminal and you will remain in insert mode, while pressing
|
||||
it once will leave insert mode.
|
||||
|
||||
Alternatively you can use the |ConqueTerm_EscKey| option to choose a
|
||||
different key for leaving insert mode. If a custom key is set, then all <Esc>
|
||||
key presses will be sent to the terminal.
|
||||
|
||||
2.3 Registering functions *conque-term-register*
|
||||
|
||||
Conque allows you to write your own VimScript functions which will be called
|
||||
at certain events. See the API section |conque-term-events| for more.
|
||||
|
||||
==============================================================================
|
||||
|
||||
3. Options *conque-term-options*
|
||||
|
||||
You can set the following options in your .vimrc (default values shown)
|
||||
|
||||
3.1 General *conque-config-general*
|
||||
|
||||
3.1.1 Python version *ConqueTerm_PyVersion*
|
||||
|
||||
Conque will work with either Python 2.x or 3.x, assuming the interfaces have
|
||||
been installed. By default it will try to use Python 2 first, then will try
|
||||
Python 3. If you want Conque to use Python 3, set this variable to 3.
|
||||
|
||||
Note: even if you set this to 3, if you don't have the python3 interface
|
||||
Conque will fall back to using Python 2.
|
||||
>
|
||||
let g:ConqueTerm_PyVersion = 2
|
||||
<
|
||||
3.1.2 Fast Mode *ConqueTerm_FastMode*
|
||||
|
||||
Disable features which could make Conque run slowly. This includes most
|
||||
terminal colors and some unicode support. Set this to 1 to enable fast mode.
|
||||
>
|
||||
let g:ConqueTerm_FastMode = 0
|
||||
<
|
||||
3.1.3 Color support *ConqueTerm_Color*
|
||||
|
||||
Terminal colors have the potential to slow down terminal screen rendering,
|
||||
depending on how many colors are used and how fast the computer is. This
|
||||
option allows you to choose how much color support will be enabled.
|
||||
|
||||
If set to 0, terminal colors will be disabled. This will allow the terminal to
|
||||
render most quickly. Syntax highlighting will still work. For example
|
||||
highlighting quoted strings or MySQL output.
|
||||
|
||||
If set to 1, terminal colors will be enabled, but only for the most recent 200
|
||||
lines of terminal output. Older output will be periodically stripped of color
|
||||
highlighting to keep the display responsive.
|
||||
|
||||
If set to 2, terminal colors will always be enabled. If your programs don't
|
||||
use color output very frequently this is a good choice.
|
||||
|
||||
Note: Color support is automatically disabled in "fast mode".
|
||||
>
|
||||
let g:ConqueTerm_Color = 1
|
||||
<
|
||||
3.1.4 Session Support *ConqueTerm_SessionSupport*
|
||||
|
||||
Vim's :mksession command allows you to save your current buffer configuration
|
||||
to a file, which can be loaded at a later time after you've closed Vim.
|
||||
|
||||
By default, Conque buffers are not restored. This is mostly for safety
|
||||
reasons; you may not want Vim to automatically re-run a destructive command.
|
||||
|
||||
However, if you're not working with missile launch code, and want Vim to
|
||||
restart your Conque buffers when you load a session file, set this variable
|
||||
to 1. Note your original subprocess and shell output will not be restored, but
|
||||
the same command will be started in your buffer.
|
||||
>
|
||||
let g:ConqueTerm_SessionSupport = 0
|
||||
<
|
||||
3.1.5 Keep updating terminal buffer *ConqueTerm_ReadUnfocused*
|
||||
|
||||
If set to 1 then your Conque buffers will continue to update after you've
|
||||
switched to another buffer.
|
||||
|
||||
Note: Conque buffers may continue to update, but they will not scroll down as
|
||||
new lines are added beyond the bottom of the visible buffer area. This is a
|
||||
limitation of the Vim scripting language for which I haven't found a
|
||||
workaround.
|
||||
>
|
||||
let g:ConqueTerm_ReadUnfocused = 1
|
||||
<
|
||||
3.1.6 Insert mode when entering buffer *ConqueTerm_InsertOnEnter*
|
||||
|
||||
If set to 1 then you will automatically go into insert mode when you enter the
|
||||
buffer. This diverges from normal Vim behavior. If 0 you will still be in
|
||||
normal mode.
|
||||
>
|
||||
let g:ConqueTerm_InsertOnEnter = 0
|
||||
<
|
||||
3.1.7 Close buffer when program exits *ConqueTerm_CloseOnEnd*
|
||||
|
||||
If you want your terminal buffer to be closed and permanently deleted when the
|
||||
program running inside of it exits, set this option to 1. Otherwise the buffer
|
||||
will become a simple text buffer after the program exits, and you can edit the
|
||||
program output in insert mode.
|
||||
>
|
||||
let g:ConqueTerm_CloseOnEnd = 0
|
||||
<
|
||||
3.1.8 Show start messages *ConqueTerm_StartMessages*
|
||||
|
||||
Display warning messages when starting up ConqueTerm if your system is
|
||||
configured incorrectly.
|
||||
>
|
||||
let g:ConqueTerm_StartMessages = 1
|
||||
<
|
||||
3.1.9 Regex for highlighting your prompt *ConqueTerm_PromptRegex*
|
||||
|
||||
Use this regular expression for sytax highlighting your terminal prompt. Your
|
||||
terminal will generally run faster if you use Vim highlighting instead of
|
||||
terminal colors for your prompt. You can also use it to do more advanced
|
||||
syntax highlighting for the prompt line.
|
||||
>
|
||||
let g:ConqueTerm_PromptRegex = '^\w\+@[0-9A-Za-z_.-]\+:[0-9A-Za-z_./\~,:-]\+\$'
|
||||
<
|
||||
3.1.10 Choose Vim syntax type *ConqueTerm_Syntax*
|
||||
|
||||
Set the buffer syntax. The default 'conque' has highlighting for MySQL, but
|
||||
not much else.
|
||||
>
|
||||
let g:ConqueTerm_Syntax = 'conque'
|
||||
<
|
||||
3.2 Keyboard *conque-config-keyboard*
|
||||
|
||||
3.2.1 The <Esc> key *ConqueTerm_EscKey*
|
||||
|
||||
If a custom key is set, then all <Esc> key presses will be sent to the
|
||||
terminal and you must use this custom key to leave insert mode. If left to the
|
||||
default value of '<Esc>' then you must press it twice to send the escape
|
||||
character to the terminal, while pressing it once will leave insert mode.
|
||||
|
||||
Note: You cannot use a key which is internally coded with the escape
|
||||
character. This includes the <F-> keys and often the <A-> and <M-> keys.
|
||||
Picking a control key, such as <C-k> will be your best bet.
|
||||
>
|
||||
let g:ConqueTerm_EscKey = '<Esc>'
|
||||
<
|
||||
3.2.2 Toggle terminal input mode *ConqueTerm_ToggleKey*
|
||||
|
||||
Press this key to pause terminal input and output display. You will then be
|
||||
able to edit the terminal screen as if it were a normal text buffer. Press
|
||||
this key again to resume terminal mode.
|
||||
>
|
||||
let g:ConqueTerm_ToggleKey = '<F8>'
|
||||
<
|
||||
3.2.3 Enable <C-w> in insert mode *ConqueTerm_CWInsert*
|
||||
|
||||
If set to 1 then you can leave the Conque buffer using the <C-w> commands
|
||||
while you're still in insert mode. If set to 0 then the <C-w> character will
|
||||
be sent to the terminal. If both this option and ConqueTerm_InsertOnEnter are
|
||||
set you can go in and out of the terminal buffer while never leaving insert
|
||||
mode.
|
||||
>
|
||||
let g:ConqueTerm_CWInsert = 0
|
||||
<
|
||||
3.2.4 Execute current file in Conque *ConqueTerm_ExecFileKey*
|
||||
|
||||
Press this key to execute the file you're currently editing in a Conque
|
||||
buffer. Is equivelent to running the command :ConqueTermSplit YOUR_FILE. Your
|
||||
file must be executable for this command to work correctly.
|
||||
>
|
||||
let g:ConqueTerm_ExecFileKey = '<F11>'
|
||||
<
|
||||
3.2.5 Send current file contents to Conque *ConqueTerm_SendFileKey*
|
||||
|
||||
Press this key to send your entire file contents to the most recently opened
|
||||
Conque buffer as keyboard input.
|
||||
>
|
||||
let g:ConqueTerm_SendFileKey = '<F10>'
|
||||
<
|
||||
3.2.6 Send selected text to Conque *ConqueTerm_SendVisKey*
|
||||
|
||||
Use this key to send the currently selected text to the most recently created
|
||||
Conque buffer.
|
||||
>
|
||||
let g:ConqueTerm_SendVisKey = '<F9>'
|
||||
<
|
||||
3.2.7 Function Keys *ConqueTerm_SendFunctionKeys*
|
||||
|
||||
By default, function keys (the F1-F12 row at the top of your keyboard) are not
|
||||
passed to the terminal. Set this option to 1 to send these key events.
|
||||
|
||||
Note: Unless you configured |ConqueTerm_SendVisKey| and |ConqueTerm_ToggleKey|
|
||||
to use different keys, <F8> and <F9> will not be sent to the terminal even if
|
||||
you set this option to 1.
|
||||
>
|
||||
let g:ConqueTerm_SendFunctionKeys = 0
|
||||
<
|
||||
3.3 Unix *conque-config-unix*
|
||||
|
||||
3.3.1 Choose your terminal type, Unix ONLY *ConqueTerm_TERM*
|
||||
|
||||
Use this option to tell Conque what type of terminal it should identify itself
|
||||
as. Conque officially uses the more limited VT100 terminal type for
|
||||
developement and testing, although it supports some more advanced features
|
||||
such as colors and title strings.
|
||||
|
||||
You can change this setting to a more advanced type, namely 'xterm', but your
|
||||
results may vary depending on which programs you're running.
|
||||
>
|
||||
let g:ConqueTerm_TERM = 'vt100'
|
||||
<
|
||||
3.4 Windows *conque-config-windows*
|
||||
|
||||
3.4.1 Python executable, Windows ONLY *ConqueTerm_PyExe*
|
||||
|
||||
The Windows version of Conque needs to know the path to the python.exe
|
||||
executable for the version of Python Conque is using. If you installed Python
|
||||
in the default location, or added the Python directory to your system path,
|
||||
Conque should be able to find python.exe without you changing this variable.
|
||||
|
||||
For example, you might set this to 'C:\Program Files\Python27\python.exe'
|
||||
>
|
||||
let g:ConqueTerm_PyExe = ''
|
||||
<
|
||||
3.4.2 Windows character code page *ConqueTerm_CodePage*
|
||||
|
||||
Set the "code page" Windows will use for your console. Leave this value set to
|
||||
zero to use the environment code page.
|
||||
|
||||
Note: Displaying unicode characters on Conque for Windows needs work.
|
||||
>
|
||||
let g:ConqueTerm_CodePage = 0
|
||||
<
|
||||
3.4.3 Terminal color method, Windows ONLY *ConqueTerm_ColorMode*
|
||||
|
||||
Vim syntax highlighting by coordinate (e.g. the 3-7th characters on the 42nd
|
||||
line) can be very slow. If you set this variable to 'conceal', you can use
|
||||
the new conceal feature to render terminal colors. Requires Vim 7.3 and only
|
||||
works on the Windows version of Conque. This will make colors render faster,
|
||||
however it will also add hidden characters to the screen, which may be
|
||||
annoying if you're copying and pasting terminal output out of the Conque
|
||||
buffer. Set this to an empty string '' to disable concealed highlighting.
|
||||
>
|
||||
let g:ConqueTerm_ColorMode = 'conceal'
|
||||
<
|
||||
==============================================================================
|
||||
|
||||
4. VimScript API (Beta) *conque-term-api*
|
||||
|
||||
The Conque scripting API allows you to create and interact with Conque
|
||||
terminals with the VimScript language. This API is still in beta stage.
|
||||
|
||||
4.1 conque_term#open({command}, [buf_opts], [remain]) *conque-term-open*
|
||||
|
||||
The open() function will create a new terminal buffer and start your command.
|
||||
|
||||
The {command} must be an executable, either an absolute path or relative to
|
||||
your system path.
|
||||
|
||||
You can pass in a list of vim commands [buf_opts] which will be executed after
|
||||
the new buffer is created but before the command is started. These are
|
||||
typically commands to alter the size, position or configuration of the buffer
|
||||
window.
|
||||
|
||||
Note: If you don't pass in a command such as 'split', the terminal will open
|
||||
in the current buffer.
|
||||
|
||||
If you don't want the new terminal buffer to become the new active buffer, set
|
||||
[remain] to 1. Only works if you create a split screen using [options].
|
||||
|
||||
Returns a Conque terminal object.
|
||||
|
||||
Examples:
|
||||
>
|
||||
let my_terminal = conque_term#open('/bin/bash')
|
||||
let my_terminal = conque_term#open('ipython', ['split', 'resize 20'], 1)
|
||||
<
|
||||
4.2 conque_term#subprocess({command}) *conque-term-subprocess*
|
||||
|
||||
Starts a new subprocess with your {command}, but no terminal buffer is ever
|
||||
created. This may be useful if you need asynchronous interaction with a
|
||||
subprocess, but want to handle the output on your own.
|
||||
|
||||
Returns a Conque terminal object.
|
||||
|
||||
Example:
|
||||
>
|
||||
let my_subprocess = conque_term#subprocess('tail -f /var/log/foo.log')
|
||||
<
|
||||
4.3 conque_term#get_instance( [terminal_number] ) *conque-term-get-instance*
|
||||
|
||||
Use the get_instance() function to retrieve an existing terminal object. The
|
||||
terminal could have been created either with the user command :ConqueTerm or
|
||||
with an API call to conque_term#open() or subprocess().
|
||||
|
||||
Use the optional [terminal_number] to retrieve a specific terminal instance.
|
||||
Otherwise if the current buffer is a Conque terminal, it will be returned,
|
||||
else the most recently created terminal. The terminal number is what you see
|
||||
at the end of a terminal buffer name, e.g. "bash - 2".
|
||||
|
||||
Returns a Conque terminal object.
|
||||
|
||||
Example:
|
||||
>
|
||||
nnoremap <F4> :call conque_term#get_instance().writeln('clear')<CR>
|
||||
<
|
||||
4.4 CONQUE_OBJECT.write({text}) *conque-term-write*
|
||||
|
||||
Once you have a terminal object from open(), subprocess() or get_instance()
|
||||
you can send text input to it with the write() method.
|
||||
|
||||
No return value.
|
||||
|
||||
Examples:
|
||||
>
|
||||
call my_terminal.write("whoami\n")
|
||||
call my_terminal.write("\<C-c>")
|
||||
<
|
||||
4.5 CONQUE_OBJECT.writeln({text}) *conque-term-writeln*
|
||||
|
||||
The same as write() except adds a \n character to the end if your input.
|
||||
|
||||
Examples:
|
||||
>
|
||||
call my_subprocess.writeln('make')
|
||||
<
|
||||
4.6 CONQUE_OBJECT.read( [timeout], [update_buffer] ) *conque-term-read*
|
||||
|
||||
Read new output from a Conque terminal subprocess. New output will be returned
|
||||
as a string, and the terminal buffer will also be updated by default.
|
||||
|
||||
If you are reading immediately after calling the write() method, you may want
|
||||
to wait [timeout] milliseconds for output to be ready.
|
||||
|
||||
If you want to prevent the output from being displayed in the terminal buffer,
|
||||
set [update_buffer] to 0. This option has no effect if the terminal was
|
||||
created with the subprocess() function, since there never is a buffer to
|
||||
update.
|
||||
|
||||
Returns output string.
|
||||
|
||||
Note: The terminal buffer will not automatically scroll down if the new output
|
||||
extends beyond the bottom of the visible buffer. Vim doesn't allow "unfocused"
|
||||
buffers to be scrolled at the current version, although hopefully this will
|
||||
change.
|
||||
|
||||
Examples:
|
||||
>
|
||||
call my_terminal.writeln('whoami')
|
||||
let output = my_terminal.read(500)
|
||||
call my_terminal.writeln('ls -lha')
|
||||
let output = my_terminal.read(1000, 1)
|
||||
<
|
||||
4.7 CONQUE_OBJECT.set_callback( {funcname} ) *conque-term-set-callback*
|
||||
|
||||
Register a callback function for this subprocess instance. This function will
|
||||
automatically be called whenever new output is available. Only practical with
|
||||
subprocess() objects.
|
||||
|
||||
Conque checkes for new subprocess output once a second when Vim is idle. If
|
||||
new output is found your function will be called.
|
||||
|
||||
Pass in the callback function name {funcname} as a string.
|
||||
|
||||
No return value.
|
||||
|
||||
Note: this method requires the g:ConqueTerm_ReadUnfocused option to be set.
|
||||
|
||||
Note: this method is experimental, results may vary.
|
||||
|
||||
Example:
|
||||
>
|
||||
let sp = conque_term#subprocess('tail -f /home/joe/log/error_log')
|
||||
|
||||
function! MyErrorAlert(output)
|
||||
echo a:output
|
||||
endfunction
|
||||
|
||||
call sp.set_callback('MyErrorAlert')
|
||||
<
|
||||
4.8 CONQUE_OBJECT.close() *conque-term-close*
|
||||
|
||||
Kill your terminal subprocess. Sends the ABORT signal. You probably want to
|
||||
close your subprocess in a more graceful manner with the write() method, but
|
||||
this can be used when needed. Does not close the terminal buffer, if it
|
||||
exists.
|
||||
|
||||
This method will be called on all existing Conque subprocesses when Vim exits.
|
||||
|
||||
Example:
|
||||
>
|
||||
let term = conque_term#open('ping google.com', ['belowright split'])
|
||||
call term.read(5000)
|
||||
call term.close()
|
||||
<
|
||||
4.9 Registering functions *conque-term-events*
|
||||
|
||||
Conque provides the option to register callback functions which will be
|
||||
executed at several different events. The currently available events are:
|
||||
|
||||
after_startup After your application has loaded into the buffer.
|
||||
buffer_enter When you switch to a Conque buffer.
|
||||
buffer_leave When you leave a Conque buffer.
|
||||
|
||||
You may use the function conque_term#register_function(event, function_name)
|
||||
to add additional hooks at a particular event. The second argument should be
|
||||
the name of a callback function which has one parameter, the current
|
||||
terminal object (see|conque-term-api|for more about terminal objects).
|
||||
|
||||
For example:
|
||||
>
|
||||
function MyConqueStartup(term)
|
||||
|
||||
" set buffer syntax using the name of the program currently running
|
||||
let syntax_associations = { 'ipython': 'python', 'irb': 'ruby' }
|
||||
|
||||
if has_key(syntax_associations, a:term.program_name)
|
||||
execute 'setlocal syntax=' . syntax_associations[a:term.program_name]
|
||||
else
|
||||
execute 'setlocal syntax=' . a:term.program_name
|
||||
endif
|
||||
|
||||
" shrink window height to 10 rows
|
||||
resize 10
|
||||
|
||||
" silly example of terminal api usage
|
||||
if a:term.program_name == 'bash'
|
||||
call a:term.writeln('svn up ~/projects/*')
|
||||
endif
|
||||
|
||||
endfunction
|
||||
|
||||
call conque_term#register_function('after_startup', 'MyConqueStartup')
|
||||
<
|
||||
|
||||
==============================================================================
|
||||
|
||||
5. Misc *conque-term-misc*
|
||||
|
||||
|
||||
5.1 Known bugs *conque-term-bugs*
|
||||
|
||||
The following are known limitations:
|
||||
|
||||
- Font/color highlighting is imperfect and slow. If you don't care about
|
||||
color in your shell, set g:ConqueTerm_Color = 0 in your .vimrc
|
||||
- Conque only supports the extended ASCII character set for input, not utf-8.
|
||||
- VT100 escape sequence support is not complete.
|
||||
- Alt/Meta key support in Vim isn't great in general, and conque is no
|
||||
exception. Pressing <Esc><Esc>x or <Esc><M-x> instead of <M-x> works in
|
||||
most cases.
|
||||
|
||||
|
||||
5.2 Contribute *conque-term-contribute*
|
||||
|
||||
The two contributions most in need are improvements to Vim itself. I currently
|
||||
use hacks to capture key press input from the user, and to poll the terminal
|
||||
for more output. The Vim todo.txt document lists proposed improvements to give
|
||||
users this behavior without hacks. Having a key press event should allow
|
||||
Conque to work with multi- byte input. If you are a Vim developer, please
|
||||
consider prioritizing these two items:
|
||||
|
||||
- todo.txt (Autocommands, line ~3137)
|
||||
8 Add an event like CursorHold that is triggered repeatedly, not just
|
||||
once after typing something.
|
||||
|
||||
|
||||
5.3 Feedback *conque-term-feedback*
|
||||
|
||||
Bugs, suggestions and patches are all welcome.
|
||||
|
||||
For more information visit http://conque.googlecode.com
|
||||
|
||||
Check out the latest from svn at http://conque.googlecode.com/svn/trunk/
|
||||
|
||||
vim:tw=78:ts=8:ft=help:norl:
|
|
@ -1,73 +0,0 @@
|
|||
|
||||
" ViM autocommands for binary plist files
|
||||
" Copyright (C) 2005 Moritz Heckscher
|
||||
"
|
||||
" Note: When a file changes externally and you answer no to vim's question if
|
||||
" you want to write anyway, the autocommands (e.g. for BufWritePost) are still
|
||||
" executed, it seems, which could have some unwanted side effects.
|
||||
"
|
||||
" This program is free software; you can redistribute it and/or modify
|
||||
" it under the terms of the GNU General Public License as published by
|
||||
" the Free Software Foundation; either version 2 of the License, or
|
||||
" (at your option) any later version.
|
||||
"
|
||||
" This program is distributed in the hope that it will be useful,
|
||||
" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
" GNU General Public License for more details.
|
||||
autocmd BufReadPre,FileReadPre *.plist set binary ft=plist syntax=xml
|
||||
" ... and call it just after editing a file in a new buffer...
|
||||
autocmd BufReadPost *.plist call MyBinaryPlistReadPost()
|
||||
" ... or when reading a file into an existing buffer (in that case, don't
|
||||
" save as binary later on).
|
||||
autocmd FileReadPost *.plist call MyBinaryPlistReadPost() | let b:saveAsBinaryPlist = 0
|
||||
autocmd BufWritePre,FileWritePre *.plist call MyBinaryPlistWritePre()
|
||||
autocmd BufWritePost,FileWritePost *.plist call MyBinaryPlistWritePost()
|
||||
|
||||
|
||||
" breaking lines etc; since setting this for normal plist files doesn't
|
||||
" hurt and it's not yet known whether or not the file to be read is stored
|
||||
" in binary format, set the option in any case to be sure).
|
||||
" Do it before editing a file in a new buffer and before reading a file
|
||||
" into in an existing buffer (using ':read foo.plist').
|
||||
|
||||
" Define a little function to convert binary files if necessary...
|
||||
fun MyBinaryPlistReadPost()
|
||||
" Check if the first line just read in indicates a binary plist
|
||||
if getline("'[") =~ "^bplist"
|
||||
" Filter lines read into buffer (convert to XML with plutil)
|
||||
'[,']!plutil -convert xml1 /dev/stdin -o /dev/stdout
|
||||
" Many people seem to want to save files originally stored
|
||||
" in binary format as such after editing, so memorize format.
|
||||
let b:saveAsBinaryPlist = 1
|
||||
endif
|
||||
" Yeah, plain text (finally or all the way through, either way...)!
|
||||
set nobinary
|
||||
" Trigger file type detection to get syntax coloring etc. according
|
||||
" to file contents (alternative: 'setfiletype xml' to force xml).
|
||||
filetype detect
|
||||
endfun
|
||||
|
||||
" Define and use functions for conversion back to binary format
|
||||
fun MyBinaryPlistWritePre()
|
||||
if exists("b:saveAsBinaryPlist") && b:saveAsBinaryPlist
|
||||
" Must set binary mode before conversion (for EOL settings)
|
||||
set binary
|
||||
" Convert buffer lines to be written to binary
|
||||
silent '[,']!plutil -convert binary1 /dev/stdin -o /dev/stdout
|
||||
" If there was a problem, e.g. when the file contains syntax
|
||||
" errors, undo the conversion and go back to nobinary so the
|
||||
" file will be saved in text format.
|
||||
if v:shell_error | undo | set nobinary | endif
|
||||
endif
|
||||
endfun
|
||||
fun MyBinaryPlistWritePost()
|
||||
" If file was to be written in binary format and there was no error
|
||||
" doing the conversion, ...
|
||||
if exists("b:saveAsBinaryPlist") && b:saveAsBinaryPlist && !v:shell_error
|
||||
" ... undo the conversion and go back to nobinary so the
|
||||
" lines are shown as text again in vim.
|
||||
undo
|
||||
set nobinary
|
||||
endif
|
||||
endfun
|
|
@ -1,160 +0,0 @@
|
|||
# coding: utf-8
|
||||
|
||||
from mccabe.mccabe import get_module_complexity
|
||||
from pyflakes import checker, messages
|
||||
import _ast
|
||||
from pep8 import pep8 as p8
|
||||
from pep8.autopep8 import fix_file as pep8_fix, fix_lines as pep8_fix_lines
|
||||
import os
|
||||
|
||||
|
||||
class Pep8Options():
|
||||
verbose = 0
|
||||
diff = False
|
||||
in_place = True
|
||||
recursive = False
|
||||
pep8_passes = 100
|
||||
max_line_length = 79
|
||||
ignore = ''
|
||||
select = ''
|
||||
aggressive = False
|
||||
|
||||
|
||||
class MccabeOptions():
|
||||
complexity = 10
|
||||
|
||||
flake_code_mapping = {
|
||||
'W402': (messages.UnusedImport,),
|
||||
'W403': (messages.ImportShadowedByLoopVar,),
|
||||
'W404': (messages.ImportStarUsed,),
|
||||
'W405': (messages.LateFutureImport,),
|
||||
'W801': (messages.RedefinedWhileUnused,
|
||||
messages.RedefinedInListComp,),
|
||||
'W802': (messages.UndefinedName,),
|
||||
'W803': (messages.UndefinedExport,),
|
||||
'W804': (messages.UndefinedLocal,
|
||||
messages.UnusedVariable,),
|
||||
'W805': (messages.DuplicateArgument,),
|
||||
'W806': (messages.Redefined,),
|
||||
}
|
||||
|
||||
flake_class_mapping = dict(
|
||||
(k, c) for (c, v) in flake_code_mapping.items() for k in v)
|
||||
|
||||
|
||||
def fix_file(filename):
|
||||
pep8_fix(filename, Pep8Options)
|
||||
|
||||
|
||||
def fix_lines(lines):
|
||||
return pep8_fix_lines(lines, Pep8Options)
|
||||
|
||||
|
||||
def run_checkers(filename, checkers, ignore):
|
||||
|
||||
result = []
|
||||
|
||||
for c in checkers:
|
||||
|
||||
checker_fun = globals().get(c)
|
||||
if not checker:
|
||||
continue
|
||||
|
||||
try:
|
||||
for e in checker_fun(filename):
|
||||
e.update(
|
||||
col=e.get('col') or 0,
|
||||
text="{0} [{1}]".format(
|
||||
e.get('text', '').strip(
|
||||
).replace("'", "\"").splitlines()[0],
|
||||
c),
|
||||
filename=os.path.normpath(filename),
|
||||
type=e.get('type') or 'W',
|
||||
bufnr=0,
|
||||
)
|
||||
result.append(e)
|
||||
except:
|
||||
pass
|
||||
|
||||
result = filter(lambda e: _ignore_error(e, ignore), result)
|
||||
return sorted(result, key=lambda x: x['lnum'])
|
||||
|
||||
|
||||
def mccabe(filename):
|
||||
return get_module_complexity(filename, min=MccabeOptions.complexity)
|
||||
|
||||
|
||||
def pep8(filename):
|
||||
style = PEP8 or _init_pep8()
|
||||
return style.input_file(filename)
|
||||
|
||||
|
||||
def pyflakes(filename):
|
||||
codeString = file(filename, 'U').read() + '\n'
|
||||
errors = []
|
||||
try:
|
||||
tree = compile(codeString, filename, "exec", _ast.PyCF_ONLY_AST)
|
||||
except SyntaxError as e:
|
||||
errors.append(dict(
|
||||
lnum=e.lineno or 0,
|
||||
col=e.offset or 0,
|
||||
text=getattr(e, 'msg', None) or str(e),
|
||||
type='E'
|
||||
))
|
||||
else:
|
||||
w = checker.Checker(tree, filename)
|
||||
w.messages.sort(lambda a, b: cmp(a.lineno, b.lineno))
|
||||
for w in w.messages:
|
||||
errors.append(dict(
|
||||
lnum=w.lineno,
|
||||
col=0,
|
||||
text=u'{0} {1}'.format(
|
||||
flake_class_mapping.get(w.__class__, ''),
|
||||
w.message % w.message_args),
|
||||
type='E'
|
||||
))
|
||||
return errors
|
||||
|
||||
|
||||
PEP8 = None
|
||||
|
||||
|
||||
def _init_pep8():
|
||||
global PEP8
|
||||
|
||||
class _PEP8Report(p8.BaseReport):
|
||||
|
||||
def init_file(self, filename, lines, expected, line_offset):
|
||||
super(_PEP8Report, self).init_file(
|
||||
filename, lines, expected, line_offset)
|
||||
self.errors = []
|
||||
|
||||
def error(self, line_number, offset, text, check):
|
||||
code = super(_PEP8Report, self).error(
|
||||
line_number, offset, text, check)
|
||||
|
||||
self.errors.append(dict(
|
||||
text=text,
|
||||
type=code,
|
||||
col=offset + 1,
|
||||
lnum=line_number,
|
||||
))
|
||||
|
||||
def get_file_results(self):
|
||||
return self.errors
|
||||
|
||||
PEP8 = p8.StyleGuide(reporter=_PEP8Report)
|
||||
return PEP8
|
||||
|
||||
|
||||
def _ignore_error(e, ignore):
|
||||
for i in ignore:
|
||||
if e['text'].startswith(i):
|
||||
return False
|
||||
return True
|
||||
|
||||
if __name__ == '__main__':
|
||||
for r in run_checkers(
|
||||
'/home/andrew/devel/vim/bundle/flake8-vim/ftplugin/python/flake8.py',
|
||||
checkers=['mccabe', 'pyflakes', 'pep8'], ignore=[]):
|
||||
print r
|
|
@ -1,188 +0,0 @@
|
|||
" Check python support
|
||||
if !has('python')
|
||||
echo "Error: PyFlake.vim required vim compiled with +python."
|
||||
finish
|
||||
endif
|
||||
|
||||
if !exists('g:PyFlakeRangeCommand')
|
||||
let g:PyFlakeRangeCommand = 'Q'
|
||||
endif
|
||||
|
||||
if !exists('b:PyFlake_initialized')
|
||||
let b:PyFlake_initialized = 1
|
||||
|
||||
au BufWritePost <buffer> call flake8#on_write()
|
||||
au CursorHold <buffer> call flake8#get_message()
|
||||
au CursorMoved <buffer> call flake8#get_message()
|
||||
|
||||
" Commands
|
||||
command! -buffer PyFlakeToggle :let b:PyFlake_disabled = exists('b:PyFlake_disabled') ? b:PyFlake_disabled ? 0 : 1 : 1
|
||||
command! -buffer PyFlake :call flake8#run()
|
||||
command! -buffer -range=% PyFlakeAuto :call flake8#auto(<line1>,<line2>)
|
||||
|
||||
" Keymaps
|
||||
if g:PyFlakeRangeCommand != ''
|
||||
exec 'vnoremap <buffer> <silent> ' . g:PyFlakeRangeCommand . ' :PyFlakeAuto<CR>'
|
||||
endif
|
||||
|
||||
let b:showing_message = 0
|
||||
|
||||
" Signs definition
|
||||
sign define W text=WW texthl=Todo
|
||||
sign define C text=CC texthl=Comment
|
||||
sign define R text=RR texthl=Visual
|
||||
sign define E text=EE texthl=Error
|
||||
endif
|
||||
|
||||
"Check for flake8 plugin is loaded
|
||||
if exists("g:PyFlakeDirectory")
|
||||
finish
|
||||
endif
|
||||
|
||||
if !exists('g:PyFlakeOnWrite')
|
||||
let g:PyFlakeOnWrite = 1
|
||||
endif
|
||||
|
||||
" Init variables
|
||||
let g:PyFlakeDirectory = expand('<sfile>:p:h')
|
||||
|
||||
if !exists('g:PyFlakeCheckers')
|
||||
let g:PyFlakeCheckers = 'pep8,mccabe,pyflakes'
|
||||
endif
|
||||
if !exists('g:PyFlakeDefaultComplexity')
|
||||
let g:PyFlakeDefaultComplexity=10
|
||||
endif
|
||||
if !exists('g:PyFlakeDisabledMessages')
|
||||
let g:PyFlakeDisabledMessages = 'E501'
|
||||
endif
|
||||
if !exists('g:PyFlakeCWindow')
|
||||
let g:PyFlakeCWindow = 6
|
||||
endif
|
||||
if !exists('g:PyFlakeSigns')
|
||||
let g:PyFlakeSigns = 1
|
||||
endif
|
||||
if !exists('g:PyFlakeMaxLineLength')
|
||||
let g:PyFlakeMaxLineLength = 100
|
||||
endif
|
||||
|
||||
python << EOF
|
||||
|
||||
import sys
|
||||
import json
|
||||
import vim
|
||||
|
||||
sys.path.insert(0, vim.eval("g:PyFlakeDirectory"))
|
||||
from flake8 import run_checkers, fix_lines, Pep8Options, MccabeOptions
|
||||
|
||||
def flake8_check():
|
||||
checkers=vim.eval('g:PyFlakeCheckers').split(',')
|
||||
ignore=vim.eval('g:PyFlakeDisabledMessages').split(',')
|
||||
MccabeOptions.complexity=int(vim.eval('g:PyFlakeDefaultComplexity'))
|
||||
Pep8Options.max_line_length=int(vim.eval('g:PyFlakeMaxLineLength'))
|
||||
filename=vim.current.buffer.name
|
||||
parse_result(run_checkers(filename, checkers, ignore))
|
||||
|
||||
def parse_result(result):
|
||||
vim.command('let g:qf_list = {}'.format(json.dumps(result, ensure_ascii=False)))
|
||||
|
||||
EOF
|
||||
|
||||
function! flake8#on_write()
|
||||
if !g:PyFlakeOnWrite || exists("b:PyFlake_disabled") && b:PyFlake_disabled
|
||||
return
|
||||
endif
|
||||
call flake8#check()
|
||||
endfunction
|
||||
|
||||
function! flake8#run()
|
||||
if &modifiable && &modified
|
||||
write
|
||||
endif
|
||||
call flake8#check()
|
||||
endfun
|
||||
|
||||
function! flake8#check()
|
||||
py flake8_check()
|
||||
let s:matchDict = {}
|
||||
for err in g:qf_list
|
||||
let s:matchDict[err.lnum] = err.text
|
||||
endfor
|
||||
call setqflist(g:qf_list, 'r')
|
||||
|
||||
" Place signs
|
||||
if g:PyFlakeSigns
|
||||
call flake8#place_signs()
|
||||
endif
|
||||
|
||||
" Open cwindow
|
||||
if g:PyFlakeCWindow
|
||||
cclose
|
||||
if len(g:qf_list)
|
||||
let l:winsize = len(g:qf_list) > g:PyFlakeCWindow ? g:PyFlakeCWindow : len(g:qf_list)
|
||||
exec l:winsize . 'cwindow'
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! flake8#auto(l1, l2) "{{{
|
||||
cclose
|
||||
sign unplace *
|
||||
let s:matchDict = {}
|
||||
call setqflist([])
|
||||
|
||||
python << EOF
|
||||
start, end = int(vim.eval('a:l1'))-1, int(vim.eval('a:l2'))
|
||||
enc = vim.eval('&enc')
|
||||
lines = fix_lines(vim.current.buffer[start:end]).splitlines()
|
||||
res = [ln.encode(enc, 'replace') for ln in lines]
|
||||
vim.current.buffer[start:end] = res
|
||||
EOF
|
||||
endfunction "}}}
|
||||
|
||||
function! flake8#place_signs()
|
||||
"first remove all sings
|
||||
sign unplace *
|
||||
|
||||
"now we place one sign for every quickfix line
|
||||
let l:id = 1
|
||||
for item in getqflist()
|
||||
execute(':sign place '.l:id.' name='.l:item.type.' line='.l:item.lnum.' buffer='.l:item.bufnr)
|
||||
let l:id = l:id + 1
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" keep track of whether or not we are showing a message
|
||||
" WideMsg() prints [long] message up to (&columns-1) length
|
||||
" guaranteed without "Press Enter" prompt.
|
||||
function! flake8#wide_msg(msg)
|
||||
let x=&ruler | let y=&showcmd
|
||||
set noruler noshowcmd
|
||||
redraw
|
||||
echo strpart(a:msg, 0, &columns-1)
|
||||
let &ruler=x | let &showcmd=y
|
||||
endfun
|
||||
|
||||
|
||||
function! flake8#get_message()
|
||||
let s:cursorPos = getpos(".")
|
||||
|
||||
" Bail if RunPyflakes hasn't been called yet.
|
||||
if !exists('s:matchDict')
|
||||
return
|
||||
endif
|
||||
|
||||
" if there's a message for the line the cursor is currently on, echo
|
||||
" it to the console
|
||||
if has_key(s:matchDict, s:cursorPos[1])
|
||||
let s:pyflakesMatch = get(s:matchDict, s:cursorPos[1])
|
||||
call flake8#wide_msg(s:pyflakesMatch)
|
||||
let b:showing_message = 1
|
||||
return
|
||||
endif
|
||||
|
||||
" otherwise, if we're showing a message, clear it
|
||||
if b:showing_message == 1
|
||||
echo
|
||||
let b:showing_message = 0
|
||||
endif
|
||||
endfunction
|
|
@ -1,446 +0,0 @@
|
|||
" -*- vim -*-
|
||||
" FILE: python.vim
|
||||
" LAST MODIFICATION: 2008-05-17 6:29pm
|
||||
" (C) Copyright 2001-2005 Mikael Berthe <bmikael@lists.lilotux.net>
|
||||
" Maintained by Jon Franklin <jvfranklin@gmail.com>
|
||||
" Version: 1.12
|
||||
|
||||
" USAGE:
|
||||
"
|
||||
" Save this file to $VIMFILES/ftplugin/python.vim. You can have multiple
|
||||
" python ftplugins by creating $VIMFILES/ftplugin/python and saving your
|
||||
" ftplugins in that directory. If saving this to the global ftplugin
|
||||
" directory, this is the recommended method, since vim ships with an
|
||||
" ftplugin/python.vim file already.
|
||||
" You can set the global variable "g:py_select_leading_comments" to 0
|
||||
" if you don't want to select comments preceding a declaration (these
|
||||
" are usually the description of the function/class).
|
||||
" You can set the global variable "g:py_select_trailing_comments" to 0
|
||||
" if you don't want to select comments at the end of a function/class.
|
||||
" If these variables are not defined, both leading and trailing comments
|
||||
" are selected.
|
||||
" Example: (in your .vimrc) "let g:py_select_leading_comments = 0"
|
||||
" You may want to take a look at the 'shiftwidth' option for the
|
||||
" shift commands...
|
||||
"
|
||||
" REQUIREMENTS:
|
||||
" vim (>= 7)
|
||||
"
|
||||
" Shortcuts:
|
||||
" ]t -- Jump to beginning of block
|
||||
" ]e -- Jump to end of block
|
||||
" ]v -- Select (Visual Line Mode) block
|
||||
" ]< -- Shift block to left
|
||||
" ]> -- Shift block to right
|
||||
" ]# -- Comment selection
|
||||
" ]u -- Uncomment selection
|
||||
" ]c -- Select current/previous class
|
||||
" ]d -- Select current/previous function
|
||||
" ]<up> -- Jump to previous line with the same/lower indentation
|
||||
" ]<down> -- Jump to next line with the same/lower indentation
|
||||
|
||||
" Only do this when not done yet for this buffer
|
||||
if exists("b:loaded_py_ftplugin")
|
||||
finish
|
||||
endif
|
||||
let b:loaded_py_ftplugin = 1
|
||||
|
||||
map ]t :PBoB<CR>
|
||||
vmap ]t :<C-U>PBOB<CR>m'gv``
|
||||
map ]e :PEoB<CR>
|
||||
vmap ]e :<C-U>PEoB<CR>m'gv``
|
||||
|
||||
map ]v ]tV]e
|
||||
map ]< ]tV]e<
|
||||
vmap ]< <
|
||||
map ]> ]tV]e>
|
||||
vmap ]> >
|
||||
|
||||
map ]# :call PythonCommentSelection()<CR>
|
||||
vmap ]# :call PythonCommentSelection()<CR>
|
||||
map ]u :call PythonUncommentSelection()<CR>
|
||||
vmap ]u :call PythonUncommentSelection()<CR>
|
||||
|
||||
map ]c :call PythonSelectObject("class")<CR>
|
||||
map ]d :call PythonSelectObject("function")<CR>
|
||||
|
||||
map ]<up> :call PythonNextLine(-1)<CR>
|
||||
map ]<down> :call PythonNextLine(1)<CR>
|
||||
" You may prefer use <s-up> and <s-down>... :-)
|
||||
|
||||
" jump to previous class
|
||||
map ]J :call PythonDec("class", -1)<CR>
|
||||
vmap ]J :call PythonDec("class", -1)<CR>
|
||||
|
||||
" jump to next class
|
||||
map ]j :call PythonDec("class", 1)<CR>
|
||||
vmap ]j :call PythonDec("class", 1)<CR>
|
||||
|
||||
" jump to previous function
|
||||
map ]F :call PythonDec("function", -1)<CR>
|
||||
vmap ]F :call PythonDec("function", -1)<CR>
|
||||
|
||||
" jump to next function
|
||||
map ]f :call PythonDec("function", 1)<CR>
|
||||
vmap ]f :call PythonDec("function", 1)<CR>
|
||||
|
||||
|
||||
|
||||
" Menu entries
|
||||
nmenu <silent> &Python.Update\ IM-Python\ Menu
|
||||
\:call UpdateMenu()<CR>
|
||||
nmenu &Python.-Sep1- :
|
||||
nmenu <silent> &Python.Beginning\ of\ Block<Tab>[t
|
||||
\]t
|
||||
nmenu <silent> &Python.End\ of\ Block<Tab>]e
|
||||
\]e
|
||||
nmenu &Python.-Sep2- :
|
||||
nmenu <silent> &Python.Shift\ Block\ Left<Tab>]<
|
||||
\]<
|
||||
vmenu <silent> &Python.Shift\ Block\ Left<Tab>]<
|
||||
\]<
|
||||
nmenu <silent> &Python.Shift\ Block\ Right<Tab>]>
|
||||
\]>
|
||||
vmenu <silent> &Python.Shift\ Block\ Right<Tab>]>
|
||||
\]>
|
||||
nmenu &Python.-Sep3- :
|
||||
vmenu <silent> &Python.Comment\ Selection<Tab>]#
|
||||
\]#
|
||||
nmenu <silent> &Python.Comment\ Selection<Tab>]#
|
||||
\]#
|
||||
vmenu <silent> &Python.Uncomment\ Selection<Tab>]u
|
||||
\]u
|
||||
nmenu <silent> &Python.Uncomment\ Selection<Tab>]u
|
||||
\]u
|
||||
nmenu &Python.-Sep4- :
|
||||
nmenu <silent> &Python.Previous\ Class<Tab>]J
|
||||
\]J
|
||||
nmenu <silent> &Python.Next\ Class<Tab>]j
|
||||
\]j
|
||||
nmenu <silent> &Python.Previous\ Function<Tab>]F
|
||||
\]F
|
||||
nmenu <silent> &Python.Next\ Function<Tab>]f
|
||||
\]f
|
||||
nmenu &Python.-Sep5- :
|
||||
nmenu <silent> &Python.Select\ Block<Tab>]v
|
||||
\]v
|
||||
nmenu <silent> &Python.Select\ Function<Tab>]d
|
||||
\]d
|
||||
nmenu <silent> &Python.Select\ Class<Tab>]c
|
||||
\]c
|
||||
nmenu &Python.-Sep6- :
|
||||
nmenu <silent> &Python.Previous\ Line\ wrt\ indent<Tab>]<up>
|
||||
\]<up>
|
||||
nmenu <silent> &Python.Next\ Line\ wrt\ indent<Tab>]<down>
|
||||
\]<down>
|
||||
|
||||
:com! PBoB execute "normal ".PythonBoB(line('.'), -1, 1)."G"
|
||||
:com! PEoB execute "normal ".PythonBoB(line('.'), 1, 1)."G"
|
||||
:com! UpdateMenu call UpdateMenu()
|
||||
|
||||
|
||||
" Go to a block boundary (-1: previous, 1: next)
|
||||
" If force_sel_comments is true, 'g:py_select_trailing_comments' is ignored
|
||||
function! PythonBoB(line, direction, force_sel_comments)
|
||||
let ln = a:line
|
||||
let ind = indent(ln)
|
||||
let mark = ln
|
||||
let indent_valid = strlen(getline(ln))
|
||||
let ln = ln + a:direction
|
||||
if (a:direction == 1) && (!a:force_sel_comments) &&
|
||||
\ exists("g:py_select_trailing_comments") &&
|
||||
\ (!g:py_select_trailing_comments)
|
||||
let sel_comments = 0
|
||||
else
|
||||
let sel_comments = 1
|
||||
endif
|
||||
|
||||
while((ln >= 1) && (ln <= line('$')))
|
||||
if (sel_comments) || (match(getline(ln), "^\\s*#") == -1)
|
||||
if (!indent_valid)
|
||||
let indent_valid = strlen(getline(ln))
|
||||
let ind = indent(ln)
|
||||
let mark = ln
|
||||
else
|
||||
if (strlen(getline(ln)))
|
||||
if (indent(ln) < ind)
|
||||
break
|
||||
endif
|
||||
let mark = ln
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
let ln = ln + a:direction
|
||||
endwhile
|
||||
|
||||
return mark
|
||||
endfunction
|
||||
|
||||
|
||||
" Go to previous (-1) or next (1) class/function definition
|
||||
function! PythonDec(obj, direction)
|
||||
if (a:obj == "class")
|
||||
let objregexp = "^\\s*class\\s\\+[a-zA-Z0-9_]\\+"
|
||||
\ . "\\s*\\((\\([a-zA-Z0-9_,. \\t\\n]\\)*)\\)\\=\\s*:"
|
||||
else
|
||||
let objregexp = "^\\s*def\\s\\+[a-zA-Z0-9_]\\+\\s*(\\_[^:#]*)\\s*:"
|
||||
endif
|
||||
let flag = "W"
|
||||
if (a:direction == -1)
|
||||
let flag = flag."b"
|
||||
endif
|
||||
let res = search(objregexp, flag)
|
||||
endfunction
|
||||
|
||||
|
||||
" Comment out selected lines
|
||||
" commentString is inserted in non-empty lines, and should be aligned with
|
||||
" the block
|
||||
function! PythonCommentSelection() range
|
||||
let commentString = "#"
|
||||
let cl = a:firstline
|
||||
let ind = 1000 " I hope nobody use so long lines! :)
|
||||
|
||||
" Look for smallest indent
|
||||
while (cl <= a:lastline)
|
||||
if strlen(getline(cl))
|
||||
let cind = indent(cl)
|
||||
let ind = ((ind < cind) ? ind : cind)
|
||||
endif
|
||||
let cl = cl + 1
|
||||
endwhile
|
||||
if (ind == 1000)
|
||||
let ind = 1
|
||||
else
|
||||
let ind = ind + 1
|
||||
endif
|
||||
|
||||
let cl = a:firstline
|
||||
execute ":".cl
|
||||
" Insert commentString in each non-empty line, in column ind
|
||||
while (cl <= a:lastline)
|
||||
if strlen(getline(cl))
|
||||
execute "normal ".ind."|i".commentString
|
||||
endif
|
||||
execute "normal \<Down>"
|
||||
let cl = cl + 1
|
||||
endwhile
|
||||
endfunction
|
||||
|
||||
" Uncomment selected lines
|
||||
function! PythonUncommentSelection() range
|
||||
" commentString could be different than the one from CommentSelection()
|
||||
" For example, this could be "# \\="
|
||||
let commentString = "#"
|
||||
let cl = a:firstline
|
||||
while (cl <= a:lastline)
|
||||
let ul = substitute(getline(cl),
|
||||
\"\\(\\s*\\)".commentString."\\(.*\\)$", "\\1\\2", "")
|
||||
call setline(cl, ul)
|
||||
let cl = cl + 1
|
||||
endwhile
|
||||
endfunction
|
||||
|
||||
|
||||
" Select an object ("class"/"function")
|
||||
function! PythonSelectObject(obj)
|
||||
" Go to the object declaration
|
||||
normal $
|
||||
call PythonDec(a:obj, -1)
|
||||
let beg = line('.')
|
||||
|
||||
if !exists("g:py_select_leading_comments") || (g:py_select_leading_comments)
|
||||
let decind = indent(beg)
|
||||
let cl = beg
|
||||
while (cl>1)
|
||||
let cl = cl - 1
|
||||
if (indent(cl) == decind) && (getline(cl)[decind] == "#")
|
||||
let beg = cl
|
||||
else
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
endif
|
||||
|
||||
if (a:obj == "class")
|
||||
let eod = "\\(^\\s*class\\s\\+[a-zA-Z0-9_]\\+\\s*"
|
||||
\ . "\\((\\([a-zA-Z0-9_,. \\t\\n]\\)*)\\)\\=\\s*\\)\\@<=:"
|
||||
else
|
||||
let eod = "\\(^\\s*def\\s\\+[a-zA-Z0-9_]\\+\\s*(\\_[^:#]*)\\s*\\)\\@<=:"
|
||||
endif
|
||||
" Look for the end of the declaration (not always the same line!)
|
||||
call search(eod, "")
|
||||
|
||||
" Is it a one-line definition?
|
||||
if match(getline('.'), "^\\s*\\(#.*\\)\\=$", col('.')) == -1
|
||||
let cl = line('.')
|
||||
execute ":".beg
|
||||
execute "normal V".cl."G"
|
||||
else
|
||||
" Select the whole block
|
||||
execute "normal \<Down>"
|
||||
let cl = line('.')
|
||||
execute ":".beg
|
||||
execute "normal V".PythonBoB(cl, 1, 0)."G"
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
" Jump to the next line with the same (or lower) indentation
|
||||
" Useful for moving between "if" and "else", for example.
|
||||
function! PythonNextLine(direction)
|
||||
let ln = line('.')
|
||||
let ind = indent(ln)
|
||||
let indent_valid = strlen(getline(ln))
|
||||
let ln = ln + a:direction
|
||||
|
||||
while((ln >= 1) && (ln <= line('$')))
|
||||
if (!indent_valid) && strlen(getline(ln))
|
||||
break
|
||||
else
|
||||
if (strlen(getline(ln)))
|
||||
if (indent(ln) <= ind)
|
||||
break
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
let ln = ln + a:direction
|
||||
endwhile
|
||||
|
||||
execute "normal ".ln."G"
|
||||
endfunction
|
||||
|
||||
function! UpdateMenu()
|
||||
" delete menu if it already exists, then rebuild it.
|
||||
" this is necessary in case you've got multiple buffers open
|
||||
" a future enhancement to this would be to make the menu aware of
|
||||
" all buffers currently open, and group classes and functions by buffer
|
||||
if exists("g:menuran")
|
||||
aunmenu IM-Python
|
||||
endif
|
||||
let restore_fe = &foldenable
|
||||
set nofoldenable
|
||||
" preserve disposition of window and cursor
|
||||
let cline=line('.')
|
||||
let ccol=col('.') - 1
|
||||
norm H
|
||||
let hline=line('.')
|
||||
" create the menu
|
||||
call MenuBuilder()
|
||||
" restore disposition of window and cursor
|
||||
exe "norm ".hline."Gzt"
|
||||
let dnscroll=cline-hline
|
||||
exe "norm ".dnscroll."j".ccol."l"
|
||||
let &foldenable = restore_fe
|
||||
endfunction
|
||||
|
||||
function! MenuBuilder()
|
||||
norm gg0
|
||||
let currentclass = -1
|
||||
let classlist = []
|
||||
let parentclass = ""
|
||||
while line(".") < line("$")
|
||||
" search for a class or function
|
||||
if match ( getline("."), '^\s*class\s\+[_a-zA-Z].*:\|^\s*def\s\+[_a-zA-Z].*:' ) != -1
|
||||
norm ^
|
||||
let linenum = line('.')
|
||||
let indentcol = col('.')
|
||||
norm "nye
|
||||
let classordef=@n
|
||||
norm w"nywge
|
||||
let objname=@n
|
||||
let parentclass = FindParentClass(classlist, indentcol)
|
||||
if classordef == "class"
|
||||
call AddClass(objname, linenum, parentclass)
|
||||
else " this is a function
|
||||
call AddFunction(objname, linenum, parentclass)
|
||||
endif
|
||||
" We actually created a menu, so lets set the global variable
|
||||
let g:menuran=1
|
||||
call RebuildClassList(classlist, [objname, indentcol], classordef)
|
||||
endif " line matched
|
||||
norm j
|
||||
endwhile
|
||||
endfunction
|
||||
|
||||
" classlist contains the list of nested classes we are in.
|
||||
" in most cases it will be empty or contain a single class
|
||||
" but where a class is nested within another, it will contain 2 or more
|
||||
" this function adds or removes classes from the list based on indentation
|
||||
function! RebuildClassList(classlist, newclass, classordef)
|
||||
let i = len(a:classlist) - 1
|
||||
while i > -1
|
||||
if a:newclass[1] <= a:classlist[i][1]
|
||||
call remove(a:classlist, i)
|
||||
endif
|
||||
let i = i - 1
|
||||
endwhile
|
||||
if a:classordef == "class"
|
||||
call add(a:classlist, a:newclass)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" we found a class or function, determine its parent class based on
|
||||
" indentation and what's contained in classlist
|
||||
function! FindParentClass(classlist, indentcol)
|
||||
let i = 0
|
||||
let parentclass = ""
|
||||
while i < len(a:classlist)
|
||||
if a:indentcol <= a:classlist[i][1]
|
||||
break
|
||||
else
|
||||
if len(parentclass) == 0
|
||||
let parentclass = a:classlist[i][0]
|
||||
else
|
||||
let parentclass = parentclass.'\.'.a:classlist[i][0]
|
||||
endif
|
||||
endif
|
||||
let i = i + 1
|
||||
endwhile
|
||||
return parentclass
|
||||
endfunction
|
||||
|
||||
" add a class to the menu
|
||||
function! AddClass(classname, lineno, parentclass)
|
||||
if len(a:parentclass) > 0
|
||||
let classstring = a:parentclass.'\.'.a:classname
|
||||
else
|
||||
let classstring = a:classname
|
||||
endif
|
||||
exe 'menu IM-Python.classes.'.classstring.' :call <SID>JumpToAndUnfold('.a:lineno.')<CR>'
|
||||
endfunction
|
||||
|
||||
" add a function to the menu, grouped by member class
|
||||
function! AddFunction(functionname, lineno, parentclass)
|
||||
if len(a:parentclass) > 0
|
||||
let funcstring = a:parentclass.'.'.a:functionname
|
||||
else
|
||||
let funcstring = a:functionname
|
||||
endif
|
||||
exe 'menu IM-Python.functions.'.funcstring.' :call <SID>JumpToAndUnfold('.a:lineno.')<CR>'
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:JumpToAndUnfold(line)
|
||||
" Go to the right line
|
||||
execute 'normal '.a:line.'gg'
|
||||
" Check to see if we are in a fold
|
||||
let lvl = foldlevel(a:line)
|
||||
if lvl != 0
|
||||
" and if so, then expand the fold out, other wise, ignore this part.
|
||||
execute 'normal 15zo'
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"" This one will work only on vim 6.2 because of the try/catch expressions.
|
||||
" function! s:JumpToAndUnfoldWithExceptions(line)
|
||||
" try
|
||||
" execute 'normal '.a:line.'gg15zo'
|
||||
" catch /^Vim\((\a\+)\)\=:E490:/
|
||||
" " Do nothing, just consume the error
|
||||
" endtry
|
||||
"endfunction
|
||||
|
||||
|
||||
" vim:set et sts=2 sw=2:
|
||||
|
|
@ -1,122 +0,0 @@
|
|||
" Vim folding file
|
||||
" Language: Python
|
||||
" Author: Jorrit Wiersma (foldexpr), Max Ischenko (foldtext), Robert
|
||||
" Ames (line counts)
|
||||
" Last Change: 2005 Jul 14
|
||||
" Version: 2.3
|
||||
" Bug fix: Drexler Christopher, Tom Schumm, Geoff Gerrietts
|
||||
|
||||
|
||||
setlocal foldmethod=expr
|
||||
setlocal foldexpr=GetPythonFold(v:lnum)
|
||||
setlocal foldtext=PythonFoldText()
|
||||
|
||||
|
||||
function! PythonFoldText()
|
||||
let line = getline(v:foldstart)
|
||||
let nnum = nextnonblank(v:foldstart + 1)
|
||||
let nextline = getline(nnum)
|
||||
if nextline =~ '^\s\+"""$'
|
||||
let line = line . getline(nnum + 1)
|
||||
elseif nextline =~ '^\s\+"""'
|
||||
let line = line . ' ' . matchstr(nextline, '"""\zs.\{-}\ze\("""\)\?$')
|
||||
elseif nextline =~ '^\s\+"[^"]\+"$'
|
||||
let line = line . ' ' . matchstr(nextline, '"\zs.*\ze"')
|
||||
elseif nextline =~ '^\s\+pass\s*$'
|
||||
let line = line . ' pass'
|
||||
endif
|
||||
let size = 1 + v:foldend - v:foldstart
|
||||
if size < 10
|
||||
let size = " " . size
|
||||
endif
|
||||
if size < 100
|
||||
let size = " " . size
|
||||
endif
|
||||
if size < 1000
|
||||
let size = " " . size
|
||||
endif
|
||||
return size . " lines: " . line
|
||||
endfunction
|
||||
|
||||
|
||||
function! GetPythonFold(lnum)
|
||||
" Determine folding level in Python source
|
||||
"
|
||||
let line = getline(a:lnum)
|
||||
let ind = indent(a:lnum)
|
||||
|
||||
" Ignore blank lines
|
||||
if line =~ '^\s*$'
|
||||
return "="
|
||||
endif
|
||||
|
||||
" Ignore triple quoted strings
|
||||
if line =~ "(\"\"\"|''')"
|
||||
return "="
|
||||
endif
|
||||
|
||||
" Ignore continuation lines
|
||||
if line =~ '\\$'
|
||||
return '='
|
||||
endif
|
||||
|
||||
" Support markers
|
||||
if line =~ '{{{'
|
||||
return "a1"
|
||||
elseif line =~ '}}}'
|
||||
return "s1"
|
||||
endif
|
||||
|
||||
" Classes and functions get their own folds
|
||||
if line =~ '^\s*\(class\|def\)\s'
|
||||
return ">" . (ind / &sw + 1)
|
||||
endif
|
||||
|
||||
let pnum = prevnonblank(a:lnum - 1)
|
||||
|
||||
if pnum == 0
|
||||
" Hit start of file
|
||||
return 0
|
||||
endif
|
||||
|
||||
" If the previous line has foldlevel zero, and we haven't increased
|
||||
" it, we should have foldlevel zero also
|
||||
if foldlevel(pnum) == 0
|
||||
return 0
|
||||
endif
|
||||
|
||||
" The end of a fold is determined through a difference in indentation
|
||||
" between this line and the next.
|
||||
" So first look for next line
|
||||
let nnum = nextnonblank(a:lnum + 1)
|
||||
if nnum == 0
|
||||
return "="
|
||||
endif
|
||||
|
||||
" First I check for some common cases where this algorithm would
|
||||
" otherwise fail. (This is all a hack)
|
||||
let nline = getline(nnum)
|
||||
if nline =~ '^\s*\(except\|else\|elif\)'
|
||||
return "="
|
||||
endif
|
||||
|
||||
" Python programmers love their readable code, so they're usually
|
||||
" going to have blank lines at the ends of functions or classes
|
||||
" If the next line isn't blank, we probably don't need to end a fold
|
||||
if nnum == a:lnum + 1
|
||||
return "="
|
||||
endif
|
||||
|
||||
" If next line has less indentation we end a fold.
|
||||
" This ends folds that aren't there a lot of the time, and this sometimes
|
||||
" confuses vim. Luckily only rarely.
|
||||
let nind = indent(nnum)
|
||||
if nind < ind
|
||||
return "<" . (nind / &sw + 1)
|
||||
endif
|
||||
|
||||
" If none of the above apply, keep the indentation
|
||||
return "="
|
||||
|
||||
endfunction
|
||||
|
|
@ -1,293 +0,0 @@
|
|||
""" Meager code path measurement tool.
|
||||
Ned Batchelder
|
||||
http://nedbatchelder.com/blog/200803/python_code_complexity_microtool.html
|
||||
MIT License.
|
||||
"""
|
||||
try:
|
||||
from compiler import parse # NOQA
|
||||
iter_child_nodes = None # NOQA
|
||||
except ImportError:
|
||||
from ast import parse, iter_child_nodes # NOQA
|
||||
|
||||
import optparse
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
|
||||
WARNING_CODE = "W901"
|
||||
|
||||
|
||||
class ASTVisitor:
|
||||
|
||||
VERBOSE = 0
|
||||
|
||||
def __init__(self):
|
||||
self.node = None
|
||||
self._cache = {}
|
||||
|
||||
def default(self, node, *args):
|
||||
if hasattr(node, 'getChildNodes'):
|
||||
children = node.getChildNodes()
|
||||
else:
|
||||
children = iter_child_nodes(node)
|
||||
|
||||
for child in children:
|
||||
self.dispatch(child, *args)
|
||||
|
||||
def dispatch(self, node, *args):
|
||||
self.node = node
|
||||
klass = node.__class__
|
||||
meth = self._cache.get(klass)
|
||||
if meth is None:
|
||||
className = klass.__name__
|
||||
meth = getattr(self.visitor, 'visit' + className, self.default)
|
||||
self._cache[klass] = meth
|
||||
|
||||
return meth(node, *args)
|
||||
|
||||
def preorder(self, tree, visitor, *args):
|
||||
"""Do preorder walk of tree using visitor"""
|
||||
self.visitor = visitor
|
||||
visitor.visit = self.dispatch
|
||||
self.dispatch(tree, *args) # XXX *args make sense?
|
||||
|
||||
|
||||
class PathNode:
|
||||
def __init__(self, name, look="circle"):
|
||||
self.name = name
|
||||
self.look = look
|
||||
|
||||
def to_dot(self):
|
||||
print('node [shape=%s,label="%s"] %d;' % \
|
||||
(self.look, self.name, self.dot_id()))
|
||||
|
||||
def dot_id(self):
|
||||
return id(self)
|
||||
|
||||
|
||||
class PathGraph:
|
||||
def __init__(self, name, entity, lineno):
|
||||
self.name = name
|
||||
self.entity = entity
|
||||
self.lineno = lineno
|
||||
self.nodes = defaultdict(list)
|
||||
|
||||
def connect(self, n1, n2):
|
||||
self.nodes[n1].append(n2)
|
||||
|
||||
def to_dot(self):
|
||||
print('subgraph {')
|
||||
for node in self.nodes:
|
||||
node.to_dot()
|
||||
for node, nexts in self.nodes.items():
|
||||
for next in nexts:
|
||||
print('%s -- %s;' % (node.dot_id(), next.dot_id()))
|
||||
print('}')
|
||||
|
||||
def complexity(self):
|
||||
""" Return the McCabe complexity for the graph.
|
||||
V-E+2
|
||||
"""
|
||||
num_edges = sum([len(n) for n in self.nodes.values()])
|
||||
num_nodes = len(self.nodes)
|
||||
return num_edges - num_nodes + 2
|
||||
|
||||
|
||||
class PathGraphingAstVisitor(ASTVisitor):
|
||||
""" A visitor for a parsed Abstract Syntax Tree which finds executable
|
||||
statements.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
ASTVisitor.__init__(self)
|
||||
self.classname = ""
|
||||
self.graphs = {}
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self.graph = None
|
||||
self.tail = None
|
||||
|
||||
def visitFunction(self, node):
|
||||
|
||||
if self.classname:
|
||||
entity = '%s%s' % (self.classname, node.name)
|
||||
else:
|
||||
entity = node.name
|
||||
|
||||
name = '%d:1: %r' % (node.lineno, entity)
|
||||
|
||||
if self.graph is not None:
|
||||
# closure
|
||||
pathnode = self.appendPathNode(name)
|
||||
self.tail = pathnode
|
||||
self.default(node)
|
||||
bottom = PathNode("", look='point')
|
||||
self.graph.connect(self.tail, bottom)
|
||||
self.graph.connect(pathnode, bottom)
|
||||
self.tail = bottom
|
||||
else:
|
||||
self.graph = PathGraph(name, entity, node.lineno)
|
||||
pathnode = PathNode(name)
|
||||
self.tail = pathnode
|
||||
self.default(node)
|
||||
self.graphs["%s%s" % (self.classname, node.name)] = self.graph
|
||||
self.reset()
|
||||
|
||||
visitFunctionDef = visitFunction
|
||||
|
||||
def visitClass(self, node):
|
||||
old_classname = self.classname
|
||||
self.classname += node.name + "."
|
||||
self.default(node)
|
||||
self.classname = old_classname
|
||||
|
||||
def appendPathNode(self, name):
|
||||
if not self.tail:
|
||||
return
|
||||
pathnode = PathNode(name)
|
||||
self.graph.connect(self.tail, pathnode)
|
||||
self.tail = pathnode
|
||||
return pathnode
|
||||
|
||||
def visitSimpleStatement(self, node):
|
||||
if node.lineno is None:
|
||||
lineno = 0
|
||||
else:
|
||||
lineno = node.lineno
|
||||
name = "Stmt %d" % lineno
|
||||
self.appendPathNode(name)
|
||||
|
||||
visitAssert = visitAssign = visitAssTuple = visitPrint = \
|
||||
visitPrintnl = visitRaise = visitSubscript = visitDecorators = \
|
||||
visitPass = visitDiscard = visitGlobal = visitReturn = \
|
||||
visitSimpleStatement
|
||||
|
||||
def visitLoop(self, node):
|
||||
name = "Loop %d" % node.lineno
|
||||
|
||||
if self.graph is None:
|
||||
# global loop
|
||||
self.graph = PathGraph(name, name, node.lineno)
|
||||
pathnode = PathNode(name)
|
||||
self.tail = pathnode
|
||||
self.default(node)
|
||||
self.graphs["%s%s" % (self.classname, name)] = self.graph
|
||||
self.reset()
|
||||
else:
|
||||
pathnode = self.appendPathNode(name)
|
||||
self.tail = pathnode
|
||||
self.default(node.body)
|
||||
bottom = PathNode("", look='point')
|
||||
self.graph.connect(self.tail, bottom)
|
||||
self.graph.connect(pathnode, bottom)
|
||||
self.tail = bottom
|
||||
|
||||
# TODO: else clause in node.else_
|
||||
|
||||
visitFor = visitWhile = visitLoop
|
||||
|
||||
def visitIf(self, node):
|
||||
name = "If %d" % node.lineno
|
||||
pathnode = self.appendPathNode(name)
|
||||
if not pathnode:
|
||||
return # TODO: figure out what to do with if's outside def's.
|
||||
loose_ends = []
|
||||
for t, n in node.tests:
|
||||
self.tail = pathnode
|
||||
self.default(n)
|
||||
loose_ends.append(self.tail)
|
||||
if node.else_:
|
||||
self.tail = pathnode
|
||||
self.default(node.else_)
|
||||
loose_ends.append(self.tail)
|
||||
else:
|
||||
loose_ends.append(pathnode)
|
||||
bottom = PathNode("", look='point')
|
||||
for le in loose_ends:
|
||||
self.graph.connect(le, bottom)
|
||||
self.tail = bottom
|
||||
|
||||
# TODO: visitTryExcept
|
||||
# TODO: visitTryFinally
|
||||
# TODO: visitWith
|
||||
|
||||
# XXX todo: determine which ones can add to the complexity
|
||||
# py2
|
||||
# TODO: visitStmt
|
||||
# TODO: visitAssName
|
||||
# TODO: visitCallFunc
|
||||
# TODO: visitConst
|
||||
|
||||
# py3
|
||||
# TODO: visitStore
|
||||
# TODO: visitCall
|
||||
# TODO: visitLoad
|
||||
# TODO: visitNum
|
||||
# TODO: visitarguments
|
||||
# TODO: visitExpr
|
||||
|
||||
|
||||
def get_code_complexity(code, min=7, filename='stdin'):
|
||||
complex = []
|
||||
try:
|
||||
ast = parse(code)
|
||||
except AttributeError:
|
||||
e = sys.exc_info()[1]
|
||||
sys.stderr.write("Unable to parse %s: %s\n" % (filename, e))
|
||||
return 0
|
||||
|
||||
visitor = PathGraphingAstVisitor()
|
||||
visitor.preorder(ast, visitor)
|
||||
for graph in visitor.graphs.values():
|
||||
if graph is None:
|
||||
# ?
|
||||
continue
|
||||
if graph.complexity() >= min:
|
||||
complex.append(dict(
|
||||
type = 'W',
|
||||
lnum = graph.lineno,
|
||||
text = '%s %r is too complex (%d)' % (
|
||||
WARNING_CODE,
|
||||
graph.entity,
|
||||
graph.complexity(),
|
||||
)
|
||||
))
|
||||
|
||||
return complex
|
||||
|
||||
|
||||
def get_module_complexity(module_path, min=7):
|
||||
"""Returns the complexity of a module"""
|
||||
code = open(module_path, "rU").read() + '\n\n'
|
||||
return get_code_complexity(code, min, filename=module_path)
|
||||
|
||||
|
||||
def main(argv):
|
||||
opar = optparse.OptionParser()
|
||||
opar.add_option("-d", "--dot", dest="dot",
|
||||
help="output a graphviz dot file", action="store_true")
|
||||
opar.add_option("-m", "--min", dest="min",
|
||||
help="minimum complexity for output", type="int",
|
||||
default=2)
|
||||
|
||||
options, args = opar.parse_args(argv)
|
||||
|
||||
text = open(args[0], "rU").read() + '\n\n'
|
||||
ast = parse(text)
|
||||
visitor = PathGraphingAstVisitor()
|
||||
visitor.preorder(ast, visitor)
|
||||
|
||||
if options.dot:
|
||||
print('graph {')
|
||||
for graph in visitor.graphs.values():
|
||||
if graph.complexity() >= options.min:
|
||||
graph.to_dot()
|
||||
print('}')
|
||||
else:
|
||||
for graph in visitor.graphs.values():
|
||||
if graph.complexity() >= options.min:
|
||||
print(graph.name, graph.complexity())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,2 +0,0 @@
|
|||
|
||||
__version__ = '0.6.1'
|
|
@ -1,130 +0,0 @@
|
|||
"""
|
||||
API for the command-line I{pyflakes} tool.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import _ast
|
||||
|
||||
from pyflakes import checker
|
||||
from pyflakes import reporter as modReporter
|
||||
|
||||
__all__ = ['check', 'checkPath', 'checkRecursive', 'iterSourceCode', 'main']
|
||||
|
||||
|
||||
def check(codeString, filename, reporter=None):
|
||||
"""
|
||||
Check the Python source given by C{codeString} for flakes.
|
||||
|
||||
@param codeString: The Python source to check.
|
||||
@type codeString: C{str}
|
||||
|
||||
@param filename: The name of the file the source came from, used to report
|
||||
errors.
|
||||
@type filename: C{str}
|
||||
|
||||
@param reporter: A L{Reporter} instance, where errors and warnings will be
|
||||
reported.
|
||||
|
||||
@return: The number of warnings emitted.
|
||||
@rtype: C{int}
|
||||
"""
|
||||
if reporter is None:
|
||||
reporter = modReporter._makeDefaultReporter()
|
||||
# First, compile into an AST and handle syntax errors.
|
||||
try:
|
||||
tree = compile(codeString, filename, "exec", _ast.PyCF_ONLY_AST)
|
||||
except SyntaxError:
|
||||
value = sys.exc_info()[1]
|
||||
msg = value.args[0]
|
||||
|
||||
(lineno, offset, text) = value.lineno, value.offset, value.text
|
||||
|
||||
# If there's an encoding problem with the file, the text is None.
|
||||
if text is None:
|
||||
# Avoid using msg, since for the only known case, it contains a
|
||||
# bogus message that claims the encoding the file declared was
|
||||
# unknown.
|
||||
reporter.unexpectedError(filename, 'problem decoding source')
|
||||
else:
|
||||
reporter.syntaxError(filename, msg, lineno, offset, text)
|
||||
return 1
|
||||
except Exception:
|
||||
reporter.unexpectedError(filename, 'problem decoding source')
|
||||
return 1
|
||||
else:
|
||||
# Okay, it's syntactically valid. Now check it.
|
||||
w = checker.Checker(tree, filename)
|
||||
w.messages.sort(key=lambda m: m.lineno)
|
||||
for warning in w.messages:
|
||||
reporter.flake(warning)
|
||||
return len(w.messages)
|
||||
|
||||
|
||||
def checkPath(filename, reporter=None):
|
||||
"""
|
||||
Check the given path, printing out any warnings detected.
|
||||
|
||||
@param reporter: A L{Reporter} instance, where errors and warnings will be
|
||||
reported.
|
||||
|
||||
@return: the number of warnings printed
|
||||
"""
|
||||
if reporter is None:
|
||||
reporter = modReporter._makeDefaultReporter()
|
||||
try:
|
||||
f = open(filename, 'U')
|
||||
try:
|
||||
return check(f.read() + '\n', filename, reporter)
|
||||
finally:
|
||||
f.close()
|
||||
except UnicodeError:
|
||||
reporter.unexpectedError(filename, 'problem decoding source')
|
||||
except IOError:
|
||||
msg = sys.exc_info()[1]
|
||||
reporter.unexpectedError(filename, msg.args[1])
|
||||
return 1
|
||||
|
||||
|
||||
def iterSourceCode(paths):
|
||||
"""
|
||||
Iterate over all Python source files in C{paths}.
|
||||
|
||||
@param paths: A list of paths. Directories will be recursed into and
|
||||
any .py files found will be yielded. Any non-directories will be
|
||||
yielded as-is.
|
||||
"""
|
||||
for path in paths:
|
||||
if os.path.isdir(path):
|
||||
for dirpath, dirnames, filenames in os.walk(path):
|
||||
for filename in filenames:
|
||||
if filename.endswith('.py'):
|
||||
yield os.path.join(dirpath, filename)
|
||||
else:
|
||||
yield path
|
||||
|
||||
|
||||
def checkRecursive(paths, reporter):
|
||||
"""
|
||||
Recursively check all source files in C{paths}.
|
||||
|
||||
@param paths: A list of paths to Python source files and directories
|
||||
containing Python source files.
|
||||
@param reporter: A L{Reporter} where all of the warnings and errors
|
||||
will be reported to.
|
||||
@return: The number of warnings found.
|
||||
"""
|
||||
warnings = 0
|
||||
for sourcePath in iterSourceCode(paths):
|
||||
warnings += checkPath(sourcePath, reporter)
|
||||
return warnings
|
||||
|
||||
|
||||
def main():
|
||||
args = sys.argv[1:]
|
||||
reporter = modReporter._makeDefaultReporter()
|
||||
if args:
|
||||
warnings = checkRecursive(args, reporter)
|
||||
else:
|
||||
warnings = check(sys.stdin.read(), '<stdin>', reporter)
|
||||
raise SystemExit(warnings > 0)
|
|
@ -1,723 +0,0 @@
|
|||
# -*- test-case-name: pyflakes -*-
|
||||
# (c) 2005-2010 Divmod, Inc.
|
||||
# See LICENSE file for details
|
||||
|
||||
import os.path
|
||||
try:
|
||||
import builtins
|
||||
PY2 = False
|
||||
except ImportError:
|
||||
import __builtin__ as builtins
|
||||
PY2 = True
|
||||
|
||||
try:
|
||||
import ast
|
||||
iter_child_nodes = ast.iter_child_nodes
|
||||
except (ImportError, AttributeError): # Python 2.5
|
||||
import _ast as ast
|
||||
|
||||
def iter_child_nodes(node, astcls=ast.AST):
|
||||
"""
|
||||
Yield all direct child nodes of *node*, that is, all fields that are nodes
|
||||
and all items of fields that are lists of nodes.
|
||||
"""
|
||||
for name in node._fields:
|
||||
field = getattr(node, name, None)
|
||||
if isinstance(field, astcls):
|
||||
yield field
|
||||
elif isinstance(field, list):
|
||||
for item in field:
|
||||
yield item
|
||||
# Python >= 3.3 uses ast.Try instead of (ast.TryExcept + ast.TryFinally)
|
||||
if hasattr(ast, 'Try'):
|
||||
ast_TryExcept = ast.Try
|
||||
ast_TryFinally = ()
|
||||
else:
|
||||
ast_TryExcept = ast.TryExcept
|
||||
ast_TryFinally = ast.TryFinally
|
||||
|
||||
from pyflakes import messages
|
||||
|
||||
|
||||
class Binding(object):
|
||||
"""
|
||||
Represents the binding of a value to a name.
|
||||
|
||||
The checker uses this to keep track of which names have been bound and
|
||||
which names have not. See L{Assignment} for a special type of binding that
|
||||
is checked with stricter rules.
|
||||
|
||||
@ivar used: pair of (L{Scope}, line-number) indicating the scope and
|
||||
line number that this binding was last used
|
||||
"""
|
||||
|
||||
def __init__(self, name, source):
|
||||
self.name = name
|
||||
self.source = source
|
||||
self.used = False
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s object %r from line %r at 0x%x>' % (self.__class__.__name__,
|
||||
self.name,
|
||||
self.source.lineno,
|
||||
id(self))
|
||||
|
||||
|
||||
class UnBinding(Binding):
|
||||
"""Created by the 'del' operator."""
|
||||
|
||||
|
||||
class Importation(Binding):
|
||||
"""
|
||||
A binding created by an import statement.
|
||||
|
||||
@ivar fullName: The complete name given to the import statement,
|
||||
possibly including multiple dotted components.
|
||||
@type fullName: C{str}
|
||||
"""
|
||||
def __init__(self, name, source):
|
||||
self.fullName = name
|
||||
name = name.split('.')[0]
|
||||
super(Importation, self).__init__(name, source)
|
||||
|
||||
|
||||
class Argument(Binding):
|
||||
"""
|
||||
Represents binding a name as an argument.
|
||||
"""
|
||||
|
||||
|
||||
class Definition(Binding):
|
||||
"""
|
||||
A binding that defines a function or a class.
|
||||
"""
|
||||
|
||||
|
||||
class Assignment(Binding):
|
||||
"""
|
||||
Represents binding a name with an explicit assignment.
|
||||
|
||||
The checker will raise warnings for any Assignment that isn't used. Also,
|
||||
the checker does not consider assignments in tuple/list unpacking to be
|
||||
Assignments, rather it treats them as simple Bindings.
|
||||
"""
|
||||
|
||||
|
||||
class FunctionDefinition(Definition):
|
||||
pass
|
||||
|
||||
|
||||
class ClassDefinition(Definition):
|
||||
pass
|
||||
|
||||
|
||||
class ExportBinding(Binding):
|
||||
"""
|
||||
A binding created by an C{__all__} assignment. If the names in the list
|
||||
can be determined statically, they will be treated as names for export and
|
||||
additional checking applied to them.
|
||||
|
||||
The only C{__all__} assignment that can be recognized is one which takes
|
||||
the value of a literal list containing literal strings. For example::
|
||||
|
||||
__all__ = ["foo", "bar"]
|
||||
|
||||
Names which are imported and not otherwise used but appear in the value of
|
||||
C{__all__} will not have an unused import warning reported for them.
|
||||
"""
|
||||
def names(self):
|
||||
"""
|
||||
Return a list of the names referenced by this binding.
|
||||
"""
|
||||
names = []
|
||||
if isinstance(self.source, ast.List):
|
||||
for node in self.source.elts:
|
||||
if isinstance(node, ast.Str):
|
||||
names.append(node.s)
|
||||
return names
|
||||
|
||||
|
||||
class Scope(dict):
|
||||
importStarred = False # set to True when import * is found
|
||||
usesLocals = False
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s at 0x%x %s>' % (self.__class__.__name__, id(self), dict.__repr__(self))
|
||||
|
||||
|
||||
class ClassScope(Scope):
|
||||
pass
|
||||
|
||||
|
||||
class FunctionScope(Scope):
|
||||
"""
|
||||
I represent a name scope for a function.
|
||||
|
||||
@ivar globals: Names declared 'global' in this function.
|
||||
"""
|
||||
def __init__(self):
|
||||
super(FunctionScope, self).__init__()
|
||||
self.globals = {}
|
||||
|
||||
|
||||
class ModuleScope(Scope):
|
||||
pass
|
||||
|
||||
|
||||
# Globally defined names which are not attributes of the builtins module, or
|
||||
# are only present on some platforms.
|
||||
_MAGIC_GLOBALS = ['__file__', '__builtins__', 'WindowsError']
|
||||
|
||||
|
||||
def getNodeName(node):
|
||||
# Returns node.id, or node.name, or None
|
||||
if hasattr(node, 'id'): # One of the many nodes with an id
|
||||
return node.id
|
||||
if hasattr(node, 'name'): # a ExceptHandler node
|
||||
return node.name
|
||||
|
||||
|
||||
class Checker(object):
|
||||
"""
|
||||
I check the cleanliness and sanity of Python code.
|
||||
|
||||
@ivar _deferredFunctions: Tracking list used by L{deferFunction}. Elements
|
||||
of the list are two-tuples. The first element is the callable passed
|
||||
to L{deferFunction}. The second element is a copy of the scope stack
|
||||
at the time L{deferFunction} was called.
|
||||
|
||||
@ivar _deferredAssignments: Similar to C{_deferredFunctions}, but for
|
||||
callables which are deferred assignment checks.
|
||||
"""
|
||||
|
||||
nodeDepth = 0
|
||||
traceTree = False
|
||||
builtIns = set(dir(builtins)) | set(_MAGIC_GLOBALS)
|
||||
|
||||
def __init__(self, tree, filename='(none)', builtins=None):
|
||||
self._deferredFunctions = []
|
||||
self._deferredAssignments = []
|
||||
self.deadScopes = []
|
||||
self.messages = []
|
||||
self.filename = filename
|
||||
if builtins:
|
||||
self.builtIns = self.builtIns.union(builtins)
|
||||
self.scopeStack = [ModuleScope()]
|
||||
self.futuresAllowed = True
|
||||
self.root = tree
|
||||
self.handleChildren(tree)
|
||||
self.runDeferred(self._deferredFunctions)
|
||||
# Set _deferredFunctions to None so that deferFunction will fail
|
||||
# noisily if called after we've run through the deferred functions.
|
||||
self._deferredFunctions = None
|
||||
self.runDeferred(self._deferredAssignments)
|
||||
# Set _deferredAssignments to None so that deferAssignment will fail
|
||||
# noisily if called after we've run through the deferred assignments.
|
||||
self._deferredAssignments = None
|
||||
del self.scopeStack[1:]
|
||||
self.popScope()
|
||||
self.checkDeadScopes()
|
||||
|
||||
def deferFunction(self, callable):
|
||||
"""
|
||||
Schedule a function handler to be called just before completion.
|
||||
|
||||
This is used for handling function bodies, which must be deferred
|
||||
because code later in the file might modify the global scope. When
|
||||
`callable` is called, the scope at the time this is called will be
|
||||
restored, however it will contain any new bindings added to it.
|
||||
"""
|
||||
self._deferredFunctions.append((callable, self.scopeStack[:]))
|
||||
|
||||
def deferAssignment(self, callable):
|
||||
"""
|
||||
Schedule an assignment handler to be called just after deferred
|
||||
function handlers.
|
||||
"""
|
||||
self._deferredAssignments.append((callable, self.scopeStack[:]))
|
||||
|
||||
def runDeferred(self, deferred):
|
||||
"""
|
||||
Run the callables in C{deferred} using their associated scope stack.
|
||||
"""
|
||||
for handler, scope in deferred:
|
||||
self.scopeStack = scope
|
||||
handler()
|
||||
|
||||
@property
|
||||
def scope(self):
|
||||
return self.scopeStack[-1]
|
||||
|
||||
def popScope(self):
|
||||
self.deadScopes.append(self.scopeStack.pop())
|
||||
|
||||
def checkDeadScopes(self):
|
||||
"""
|
||||
Look at scopes which have been fully examined and report names in them
|
||||
which were imported but unused.
|
||||
"""
|
||||
for scope in self.deadScopes:
|
||||
export = isinstance(scope.get('__all__'), ExportBinding)
|
||||
if export:
|
||||
all = scope['__all__'].names()
|
||||
if not scope.importStarred and os.path.basename(self.filename) != '__init__.py':
|
||||
# Look for possible mistakes in the export list
|
||||
undefined = set(all) - set(scope)
|
||||
for name in undefined:
|
||||
self.report(messages.UndefinedExport,
|
||||
scope['__all__'].source.lineno, name)
|
||||
else:
|
||||
all = []
|
||||
|
||||
# Look for imported names that aren't used.
|
||||
for importation in scope.values():
|
||||
if isinstance(importation, Importation):
|
||||
if not importation.used and importation.name not in all:
|
||||
self.report(messages.UnusedImport,
|
||||
importation.source.lineno, importation.name)
|
||||
|
||||
def pushFunctionScope(self):
|
||||
self.scopeStack.append(FunctionScope())
|
||||
|
||||
def pushClassScope(self):
|
||||
self.scopeStack.append(ClassScope())
|
||||
|
||||
def report(self, messageClass, *args, **kwargs):
|
||||
self.messages.append(messageClass(self.filename, *args, **kwargs))
|
||||
|
||||
def hasParent(self, node, kind):
|
||||
while hasattr(node, 'parent'):
|
||||
node = node.parent
|
||||
if isinstance(node, kind):
|
||||
return True
|
||||
|
||||
def getCommonAncestor(self, lnode, rnode, stop=None):
|
||||
if not stop:
|
||||
stop = self.root
|
||||
if lnode is rnode:
|
||||
return lnode
|
||||
if stop in (lnode, rnode):
|
||||
return stop
|
||||
|
||||
if not hasattr(lnode, 'parent') or not hasattr(rnode, 'parent'):
|
||||
return
|
||||
if (lnode.level > rnode.level):
|
||||
return self.getCommonAncestor(lnode.parent, rnode, stop)
|
||||
if (rnode.level > lnode.level):
|
||||
return self.getCommonAncestor(lnode, rnode.parent, stop)
|
||||
return self.getCommonAncestor(lnode.parent, rnode.parent, stop)
|
||||
|
||||
def descendantOf(self, node, ancestors, stop=None):
|
||||
for a in ancestors:
|
||||
if self.getCommonAncestor(node, a, stop) not in (stop, None):
|
||||
return True
|
||||
return False
|
||||
|
||||
def onFork(self, parent, lnode, rnode, items):
|
||||
return (self.descendantOf(lnode, items, parent) ^
|
||||
self.descendantOf(rnode, items, parent))
|
||||
|
||||
def differentForks(self, lnode, rnode):
|
||||
"""True, if lnode and rnode are located on different forks of IF/TRY"""
|
||||
ancestor = self.getCommonAncestor(lnode, rnode)
|
||||
if isinstance(ancestor, ast.If):
|
||||
for fork in (ancestor.body, ancestor.orelse):
|
||||
if self.onFork(ancestor, lnode, rnode, fork):
|
||||
return True
|
||||
elif isinstance(ancestor, ast_TryExcept):
|
||||
body = ancestor.body + ancestor.orelse
|
||||
for fork in [body] + [[hdl] for hdl in ancestor.handlers]:
|
||||
if self.onFork(ancestor, lnode, rnode, fork):
|
||||
return True
|
||||
elif isinstance(ancestor, ast_TryFinally):
|
||||
if self.onFork(ancestor, lnode, rnode, ancestor.body):
|
||||
return True
|
||||
return False
|
||||
|
||||
def addBinding(self, node, value, reportRedef=True):
|
||||
"""
|
||||
Called when a binding is altered.
|
||||
|
||||
- `node` is the statement responsible for the change
|
||||
- `value` is the optional new value, a Binding instance, associated
|
||||
with the binding; if None, the binding is deleted if it exists.
|
||||
- if `reportRedef` is True (default), rebinding while unused will be
|
||||
reported.
|
||||
"""
|
||||
redefinedWhileUnused = False
|
||||
if not isinstance(self.scope, ClassScope):
|
||||
for scope in self.scopeStack[::-1]:
|
||||
existing = scope.get(value.name)
|
||||
if (isinstance(existing, Importation)
|
||||
and not existing.used
|
||||
and (not isinstance(value, Importation) or value.fullName == existing.fullName)
|
||||
and reportRedef
|
||||
and not self.differentForks(node, existing.source)):
|
||||
redefinedWhileUnused = True
|
||||
self.report(messages.RedefinedWhileUnused,
|
||||
node.lineno, value.name, existing.source.lineno)
|
||||
|
||||
existing = self.scope.get(value.name)
|
||||
if not redefinedWhileUnused and self.hasParent(value.source, ast.ListComp):
|
||||
if (existing and reportRedef
|
||||
and not self.hasParent(existing.source, (ast.For, ast.ListComp))):
|
||||
self.report(messages.RedefinedInListComp,
|
||||
node.lineno, value.name, existing.source.lineno)
|
||||
|
||||
if isinstance(value, UnBinding):
|
||||
try:
|
||||
del self.scope[value.name]
|
||||
except KeyError:
|
||||
self.report(messages.UndefinedName, node.lineno, value.name)
|
||||
elif (isinstance(existing, Definition)
|
||||
and not existing.used
|
||||
and not self.differentForks(node, existing.source)):
|
||||
self.report(messages.RedefinedWhileUnused,
|
||||
node.lineno, value.name, existing.source.lineno)
|
||||
else:
|
||||
self.scope[value.name] = value
|
||||
|
||||
def handleNodeLoad(self, node):
|
||||
name = getNodeName(node)
|
||||
if not name:
|
||||
return
|
||||
# try local scope
|
||||
importStarred = self.scope.importStarred
|
||||
try:
|
||||
self.scope[name].used = (self.scope, node.lineno)
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
return
|
||||
|
||||
# try enclosing function scopes
|
||||
for scope in self.scopeStack[-2:0:-1]:
|
||||
importStarred = importStarred or scope.importStarred
|
||||
if not isinstance(scope, FunctionScope):
|
||||
continue
|
||||
try:
|
||||
scope[name].used = (self.scope, node.lineno)
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
return
|
||||
|
||||
# try global scope
|
||||
importStarred = importStarred or self.scopeStack[0].importStarred
|
||||
try:
|
||||
self.scopeStack[0][name].used = (self.scope, node.lineno)
|
||||
except KeyError:
|
||||
if not importStarred and name not in self.builtIns:
|
||||
if (os.path.basename(self.filename) == '__init__.py' and name == '__path__'):
|
||||
# the special name __path__ is valid only in packages
|
||||
pass
|
||||
else:
|
||||
self.report(messages.UndefinedName, node.lineno, name)
|
||||
|
||||
def handleNodeStore(self, node):
|
||||
name = getNodeName(node)
|
||||
if not name:
|
||||
return
|
||||
# if the name hasn't already been defined in the current scope
|
||||
if isinstance(self.scope, FunctionScope) and name not in self.scope:
|
||||
# for each function or module scope above us
|
||||
for scope in self.scopeStack[:-1]:
|
||||
if not isinstance(scope, (FunctionScope, ModuleScope)):
|
||||
continue
|
||||
# if the name was defined in that scope, and the name has
|
||||
# been accessed already in the current scope, and hasn't
|
||||
# been declared global
|
||||
if (name in scope and scope[name].used and scope[name].used[0] is self.scope
|
||||
and name not in self.scope.globals):
|
||||
# then it's probably a mistake
|
||||
self.report(messages.UndefinedLocal,
|
||||
scope[name].used[1], name, scope[name].source.lineno)
|
||||
break
|
||||
|
||||
parent = getattr(node, 'parent', None)
|
||||
if isinstance(parent, (ast.For, ast.comprehension, ast.Tuple, ast.List)):
|
||||
binding = Binding(name, node)
|
||||
elif parent is not None and name == '__all__' and isinstance(self.scope, ModuleScope):
|
||||
binding = ExportBinding(name, parent.value)
|
||||
else:
|
||||
binding = Assignment(name, node)
|
||||
if name in self.scope:
|
||||
binding.used = self.scope[name].used
|
||||
self.addBinding(node, binding)
|
||||
|
||||
def handleNodeDelete(self, node):
|
||||
name = getNodeName(node)
|
||||
if not name:
|
||||
return
|
||||
if isinstance(self.scope, FunctionScope) and name in self.scope.globals:
|
||||
del self.scope.globals[name]
|
||||
else:
|
||||
self.addBinding(node, UnBinding(name, node))
|
||||
|
||||
def handleChildren(self, tree):
|
||||
for node in iter_child_nodes(tree):
|
||||
self.handleNode(node, tree)
|
||||
|
||||
def isDocstring(self, node):
|
||||
"""
|
||||
Determine if the given node is a docstring, as long as it is at the
|
||||
correct place in the node tree.
|
||||
"""
|
||||
return isinstance(node, ast.Str) or (isinstance(node, ast.Expr) and
|
||||
isinstance(node.value, ast.Str))
|
||||
|
||||
def handleNode(self, node, parent):
|
||||
if node is None:
|
||||
return
|
||||
node.parent = parent
|
||||
if self.traceTree:
|
||||
print(' ' * self.nodeDepth + node.__class__.__name__)
|
||||
self.nodeDepth += 1
|
||||
if self.futuresAllowed and not (isinstance(node, ast.ImportFrom) or
|
||||
self.isDocstring(node)):
|
||||
self.futuresAllowed = False
|
||||
nodeType = node.__class__.__name__.upper()
|
||||
node.level = self.nodeDepth
|
||||
try:
|
||||
handler = getattr(self, nodeType)
|
||||
handler(node)
|
||||
finally:
|
||||
self.nodeDepth -= 1
|
||||
if self.traceTree:
|
||||
print(' ' * self.nodeDepth + 'end ' + node.__class__.__name__)
|
||||
|
||||
def ignore(self, node):
|
||||
pass
|
||||
|
||||
# "stmt" type nodes
|
||||
RETURN = DELETE = PRINT = WHILE = IF = WITH = WITHITEM = RAISE = \
|
||||
TRYEXCEPT = TRYFINALLY = TRY = ASSERT = EXEC = EXPR = handleChildren
|
||||
|
||||
CONTINUE = BREAK = PASS = ignore
|
||||
|
||||
# "expr" type nodes
|
||||
BOOLOP = BINOP = UNARYOP = IFEXP = DICT = SET = YIELD = YIELDFROM = \
|
||||
COMPARE = CALL = REPR = ATTRIBUTE = SUBSCRIPT = LIST = TUPLE = \
|
||||
STARRED = handleChildren
|
||||
|
||||
NUM = STR = BYTES = ELLIPSIS = ignore
|
||||
|
||||
# "slice" type nodes
|
||||
SLICE = EXTSLICE = INDEX = handleChildren
|
||||
|
||||
# expression contexts are node instances too, though being constants
|
||||
LOAD = STORE = DEL = AUGLOAD = AUGSTORE = PARAM = ignore
|
||||
|
||||
# same for operators
|
||||
AND = OR = ADD = SUB = MULT = DIV = MOD = POW = LSHIFT = RSHIFT = \
|
||||
BITOR = BITXOR = BITAND = FLOORDIV = INVERT = NOT = UADD = USUB = \
|
||||
EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = ignore
|
||||
|
||||
# additional node types
|
||||
COMPREHENSION = KEYWORD = handleChildren
|
||||
|
||||
def GLOBAL(self, node):
|
||||
"""
|
||||
Keep track of globals declarations.
|
||||
"""
|
||||
if isinstance(self.scope, FunctionScope):
|
||||
self.scope.globals.update(dict.fromkeys(node.names))
|
||||
|
||||
NONLOCAL = GLOBAL
|
||||
|
||||
def LISTCOMP(self, node):
|
||||
# handle generators before element
|
||||
for gen in node.generators:
|
||||
self.handleNode(gen, node)
|
||||
self.handleNode(node.elt, node)
|
||||
|
||||
GENERATOREXP = SETCOMP = LISTCOMP
|
||||
|
||||
def DICTCOMP(self, node):
|
||||
for gen in node.generators:
|
||||
self.handleNode(gen, node)
|
||||
self.handleNode(node.key, node)
|
||||
self.handleNode(node.value, node)
|
||||
|
||||
def FOR(self, node):
|
||||
"""
|
||||
Process bindings for loop variables.
|
||||
"""
|
||||
vars = []
|
||||
|
||||
def collectLoopVars(n):
|
||||
if isinstance(n, ast.Name):
|
||||
vars.append(n.id)
|
||||
elif isinstance(n, ast.expr_context):
|
||||
return
|
||||
else:
|
||||
for c in iter_child_nodes(n):
|
||||
collectLoopVars(c)
|
||||
|
||||
collectLoopVars(node.target)
|
||||
for varn in vars:
|
||||
if (isinstance(self.scope.get(varn), Importation)
|
||||
# unused ones will get an unused import warning
|
||||
and self.scope[varn].used):
|
||||
self.report(messages.ImportShadowedByLoopVar,
|
||||
node.lineno, varn, self.scope[varn].source.lineno)
|
||||
|
||||
self.handleChildren(node)
|
||||
|
||||
def NAME(self, node):
|
||||
"""
|
||||
Handle occurrence of Name (which can be a load/store/delete access.)
|
||||
"""
|
||||
if node.id == 'locals' and isinstance(node.parent, ast.Call):
|
||||
# we are doing locals() call in current scope
|
||||
self.scope.usesLocals = True
|
||||
# Locate the name in locals / function / globals scopes.
|
||||
if isinstance(node.ctx, (ast.Load, ast.AugLoad)):
|
||||
self.handleNodeLoad(node)
|
||||
elif isinstance(node.ctx, (ast.Store, ast.AugStore)):
|
||||
self.handleNodeStore(node)
|
||||
elif isinstance(node.ctx, ast.Del):
|
||||
self.handleNodeDelete(node)
|
||||
else:
|
||||
# must be a Param context -- this only happens for names in function
|
||||
# arguments, but these aren't dispatched through here
|
||||
raise RuntimeError("Got impossible expression context: %r" % (node.ctx,))
|
||||
|
||||
def FUNCTIONDEF(self, node):
|
||||
if not hasattr(node, 'decorator_list'): # Python 2.5
|
||||
node.decorator_list = node.decorators
|
||||
for deco in node.decorator_list:
|
||||
self.handleNode(deco, node)
|
||||
self.addBinding(node, FunctionDefinition(node.name, node))
|
||||
self.LAMBDA(node)
|
||||
|
||||
def LAMBDA(self, node):
|
||||
args = []
|
||||
|
||||
if PY2:
|
||||
def addArgs(arglist):
|
||||
for arg in arglist:
|
||||
if isinstance(arg, ast.Tuple):
|
||||
addArgs(arg.elts)
|
||||
else:
|
||||
if arg.id in args:
|
||||
self.report(messages.DuplicateArgument,
|
||||
node.lineno, arg.id)
|
||||
args.append(arg.id)
|
||||
addArgs(node.args.args)
|
||||
defaults = node.args.defaults
|
||||
else:
|
||||
for arg in node.args.args + node.args.kwonlyargs:
|
||||
if arg.arg in args:
|
||||
self.report(messages.DuplicateArgument,
|
||||
node.lineno, arg.arg)
|
||||
args.append(arg.arg)
|
||||
self.handleNode(arg.annotation, node)
|
||||
if hasattr(node, 'returns'): # Only for FunctionDefs
|
||||
for annotation in (node.args.varargannotation,
|
||||
node.args.kwargannotation, node.returns):
|
||||
self.handleNode(annotation, node)
|
||||
defaults = node.args.defaults + node.args.kw_defaults
|
||||
|
||||
# vararg/kwarg identifiers are not Name nodes
|
||||
for wildcard in (node.args.vararg, node.args.kwarg):
|
||||
if not wildcard:
|
||||
continue
|
||||
if wildcard in args:
|
||||
self.report(messages.DuplicateArgument, node.lineno, wildcard)
|
||||
args.append(wildcard)
|
||||
for default in defaults:
|
||||
self.handleNode(default, node)
|
||||
|
||||
def runFunction():
|
||||
|
||||
self.pushFunctionScope()
|
||||
for name in args:
|
||||
self.addBinding(node, Argument(name, node), reportRedef=False)
|
||||
if isinstance(node.body, list):
|
||||
# case for FunctionDefs
|
||||
for stmt in node.body:
|
||||
self.handleNode(stmt, node)
|
||||
else:
|
||||
# case for Lambdas
|
||||
self.handleNode(node.body, node)
|
||||
|
||||
def checkUnusedAssignments():
|
||||
"""
|
||||
Check to see if any assignments have not been used.
|
||||
"""
|
||||
for name, binding in self.scope.items():
|
||||
if (not binding.used and name not in self.scope.globals
|
||||
and not self.scope.usesLocals
|
||||
and isinstance(binding, Assignment)):
|
||||
self.report(messages.UnusedVariable,
|
||||
binding.source.lineno, name)
|
||||
self.deferAssignment(checkUnusedAssignments)
|
||||
self.popScope()
|
||||
|
||||
self.deferFunction(runFunction)
|
||||
|
||||
def CLASSDEF(self, node):
|
||||
"""
|
||||
Check names used in a class definition, including its decorators, base
|
||||
classes, and the body of its definition. Additionally, add its name to
|
||||
the current scope.
|
||||
"""
|
||||
# no class decorator in Python 2.5
|
||||
for deco in getattr(node, 'decorator_list', ''):
|
||||
self.handleNode(deco, node)
|
||||
for baseNode in node.bases:
|
||||
self.handleNode(baseNode, node)
|
||||
if not PY2:
|
||||
for keywordNode in node.keywords:
|
||||
self.handleNode(keywordNode, node)
|
||||
self.pushClassScope()
|
||||
for stmt in node.body:
|
||||
self.handleNode(stmt, node)
|
||||
self.popScope()
|
||||
self.addBinding(node, ClassDefinition(node.name, node))
|
||||
|
||||
def ASSIGN(self, node):
|
||||
self.handleNode(node.value, node)
|
||||
for target in node.targets:
|
||||
self.handleNode(target, node)
|
||||
|
||||
def AUGASSIGN(self, node):
|
||||
self.handleNodeLoad(node.target)
|
||||
self.handleNode(node.value, node)
|
||||
self.handleNode(node.target, node)
|
||||
|
||||
def IMPORT(self, node):
|
||||
for alias in node.names:
|
||||
name = alias.asname or alias.name
|
||||
importation = Importation(name, node)
|
||||
self.addBinding(node, importation)
|
||||
|
||||
def IMPORTFROM(self, node):
|
||||
if node.module == '__future__':
|
||||
if not self.futuresAllowed:
|
||||
self.report(messages.LateFutureImport,
|
||||
node.lineno, [n.name for n in node.names])
|
||||
else:
|
||||
self.futuresAllowed = False
|
||||
|
||||
for alias in node.names:
|
||||
if alias.name == '*':
|
||||
self.scope.importStarred = True
|
||||
self.report(messages.ImportStarUsed, node.lineno, node.module)
|
||||
continue
|
||||
name = alias.asname or alias.name
|
||||
importation = Importation(name, node)
|
||||
if node.module == '__future__':
|
||||
importation.used = (self.scope, node.lineno)
|
||||
self.addBinding(node, importation)
|
||||
|
||||
def EXCEPTHANDLER(self, node):
|
||||
# 3.x: in addition to handling children, we must handle the name of
|
||||
# the exception, which is not a Name node, but a simple string.
|
||||
if isinstance(node.name, str):
|
||||
self.handleNodeStore(node)
|
||||
self.handleChildren(node)
|
|
@ -1,113 +0,0 @@
|
|||
# (c) 2005 Divmod, Inc. See LICENSE file for details
|
||||
|
||||
|
||||
class Message(object):
|
||||
message = ''
|
||||
message_args = ()
|
||||
|
||||
def __init__(self, filename, lineno):
|
||||
self.filename = filename
|
||||
self.lineno = lineno
|
||||
|
||||
def __str__(self):
|
||||
return '%s:%s: %s' % (self.filename, self.lineno, self.message % self.message_args)
|
||||
|
||||
|
||||
class UnusedImport(Message):
|
||||
message = '%r imported but unused'
|
||||
|
||||
def __init__(self, filename, lineno, name):
|
||||
Message.__init__(self, filename, lineno)
|
||||
self.message_args = (name,)
|
||||
|
||||
|
||||
class RedefinedWhileUnused(Message):
|
||||
message = 'redefinition of unused %r from line %r'
|
||||
|
||||
def __init__(self, filename, lineno, name, orig_lineno):
|
||||
Message.__init__(self, filename, lineno)
|
||||
self.message_args = (name, orig_lineno)
|
||||
|
||||
|
||||
class RedefinedInListComp(Message):
|
||||
message = 'list comprehension redefines %r from line %r'
|
||||
|
||||
def __init__(self, filename, lineno, name, orig_lineno):
|
||||
Message.__init__(self, filename, lineno)
|
||||
self.message_args = (name, orig_lineno)
|
||||
|
||||
|
||||
class ImportShadowedByLoopVar(Message):
|
||||
message = 'import %r from line %r shadowed by loop variable'
|
||||
|
||||
def __init__(self, filename, lineno, name, orig_lineno):
|
||||
Message.__init__(self, filename, lineno)
|
||||
self.message_args = (name, orig_lineno)
|
||||
|
||||
|
||||
class ImportStarUsed(Message):
|
||||
message = "'from %s import *' used; unable to detect undefined names"
|
||||
|
||||
def __init__(self, filename, lineno, modname):
|
||||
Message.__init__(self, filename, lineno)
|
||||
self.message_args = (modname,)
|
||||
|
||||
|
||||
class UndefinedName(Message):
|
||||
message = 'undefined name %r'
|
||||
|
||||
def __init__(self, filename, lineno, name):
|
||||
Message.__init__(self, filename, lineno)
|
||||
self.message_args = (name,)
|
||||
|
||||
|
||||
class UndefinedExport(Message):
|
||||
message = 'undefined name %r in __all__'
|
||||
|
||||
def __init__(self, filename, lineno, name):
|
||||
Message.__init__(self, filename, lineno)
|
||||
self.message_args = (name,)
|
||||
|
||||
|
||||
class UndefinedLocal(Message):
|
||||
message = "local variable %r (defined in enclosing scope on line %r) referenced before assignment"
|
||||
|
||||
def __init__(self, filename, lineno, name, orig_lineno):
|
||||
Message.__init__(self, filename, lineno)
|
||||
self.message_args = (name, orig_lineno)
|
||||
|
||||
|
||||
class DuplicateArgument(Message):
|
||||
message = 'duplicate argument %r in function definition'
|
||||
|
||||
def __init__(self, filename, lineno, name):
|
||||
Message.__init__(self, filename, lineno)
|
||||
self.message_args = (name,)
|
||||
|
||||
|
||||
class Redefined(Message):
|
||||
message = 'redefinition of %r from line %r'
|
||||
|
||||
def __init__(self, filename, lineno, name, orig_lineno):
|
||||
Message.__init__(self, filename, lineno)
|
||||
self.message_args = (name, orig_lineno)
|
||||
|
||||
|
||||
class LateFutureImport(Message):
|
||||
message = 'future import(s) %r after other statements'
|
||||
|
||||
def __init__(self, filename, lineno, names):
|
||||
Message.__init__(self, filename, lineno)
|
||||
self.message_args = (names,)
|
||||
|
||||
|
||||
class UnusedVariable(Message):
|
||||
"""
|
||||
Indicates that a variable has been explicity assigned to but not actually
|
||||
used.
|
||||
"""
|
||||
message = 'local variable %r is assigned to but never used'
|
||||
|
||||
def __init__(self, filename, lineno, names):
|
||||
Message.__init__(self, filename, lineno)
|
||||
self.message_args = (names,)
|
|
@ -1,79 +0,0 @@
|
|||
# (c) 2005-2012 Divmod, Inc.
|
||||
# See LICENSE file for details
|
||||
|
||||
import sys
|
||||
try:
|
||||
u = unicode
|
||||
except NameError:
|
||||
u = str
|
||||
|
||||
|
||||
class Reporter(object):
|
||||
"""
|
||||
Formats the results of pyflakes checks to users.
|
||||
"""
|
||||
|
||||
def __init__(self, warningStream, errorStream):
|
||||
"""
|
||||
Construct a L{Reporter}.
|
||||
|
||||
@param warningStream: A file-like object where warnings will be
|
||||
written to. The stream's C{write} method must accept unicode.
|
||||
C{sys.stdout} is a good value.
|
||||
@param errorStream: A file-like object where error output will be
|
||||
written to. The stream's C{write} method must accept unicode.
|
||||
C{sys.stderr} is a good value.
|
||||
"""
|
||||
self._stdout = warningStream
|
||||
self._stderr = errorStream
|
||||
|
||||
def unexpectedError(self, filename, msg):
|
||||
"""
|
||||
An unexpected error occurred trying to process C{filename}.
|
||||
|
||||
@param filename: The path to a file that we could not process.
|
||||
@ptype filename: C{unicode}
|
||||
@param msg: A message explaining the problem.
|
||||
@ptype msg: C{unicode}
|
||||
"""
|
||||
self._stderr.write(u("%s: %s\n") % (filename, msg))
|
||||
|
||||
def syntaxError(self, filename, msg, lineno, offset, text):
|
||||
"""
|
||||
There was a syntax errror in C{filename}.
|
||||
|
||||
@param filename: The path to the file with the syntax error.
|
||||
@ptype filename: C{unicode}
|
||||
@param msg: An explanation of the syntax error.
|
||||
@ptype msg: C{unicode}
|
||||
@param lineno: The line number where the syntax error occurred.
|
||||
@ptype lineno: C{int}
|
||||
@param offset: The column on which the syntax error occurred.
|
||||
@ptype offset: C{int}
|
||||
@param text: The source code containing the syntax error.
|
||||
@ptype text: C{unicode}
|
||||
"""
|
||||
line = text.splitlines()[-1]
|
||||
if offset is not None:
|
||||
offset = offset - (len(text) - len(line))
|
||||
self._stderr.write(u('%s:%d: %s\n') % (filename, lineno, msg))
|
||||
self._stderr.write(u(line))
|
||||
self._stderr.write(u('\n'))
|
||||
if offset is not None:
|
||||
self._stderr.write(u(" " * (offset + 1) + "^\n"))
|
||||
|
||||
def flake(self, message):
|
||||
"""
|
||||
pyflakes found something wrong with the code.
|
||||
|
||||
@param: A L{pyflakes.messages.Message}.
|
||||
"""
|
||||
self._stdout.write(u(message))
|
||||
self._stdout.write(u('\n'))
|
||||
|
||||
|
||||
def _makeDefaultReporter():
|
||||
"""
|
||||
Make a reporter that can be used when no reporter is specified.
|
||||
"""
|
||||
return Reporter(sys.stdout, sys.stderr)
|
3
gvimrc
3
gvimrc
|
@ -32,9 +32,10 @@ if &background == "dark"
|
|||
hi normal guibg=black
|
||||
endif
|
||||
|
||||
colorscheme Tomorrow-Night-Eighties
|
||||
" colorscheme railscasts
|
||||
" colorscheme zenburn
|
||||
colorscheme freya
|
||||
" colorscheme freya
|
||||
" colorscheme southwest-fog
|
||||
" colorscheme moria
|
||||
" colorscheme morning
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
" ---------------------------------------------------------------------
|
||||
" getscriptPlugin.vim
|
||||
" Author: Charles E. Campbell, Jr.
|
||||
" Date: Jan 07, 2008
|
||||
" Installing: :help glvs-install
|
||||
" Usage: :help glvs
|
||||
"
|
||||
" GetLatestVimScripts: 642 1 :AutoInstall: getscript.vim
|
||||
"
|
||||
" (Rom 15:11 WEB) Again, "Praise the Lord, all you Gentiles! Let
|
||||
" all the peoples praise Him."
|
||||
" ---------------------------------------------------------------------
|
||||
" Initialization: {{{1
|
||||
" if you're sourcing this file, surely you can't be
|
||||
" expecting vim to be in its vi-compatible mode
|
||||
if &cp || exists("g:loaded_getscriptPlugin")
|
||||
if &verbose
|
||||
echo "GetLatestVimScripts is not vi-compatible; not loaded (you need to set nocp)"
|
||||
endif
|
||||
finish
|
||||
endif
|
||||
let g:loaded_getscriptPlugin = "v33"
|
||||
let s:keepcpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
" ---------------------------------------------------------------------
|
||||
" Public Interface: {{{1
|
||||
com! -nargs=0 GetLatestVimScripts call getscript#GetLatestVimScripts()
|
||||
com! -nargs=0 GetScripts call getscript#GetLatestVimScripts()
|
||||
silent! com -nargs=0 GLVS call getscript#GetLatestVimScripts()
|
||||
|
||||
" ---------------------------------------------------------------------
|
||||
" Restore Options: {{{1
|
||||
let &cpo= s:keepcpo
|
||||
unlet s:keepcpo
|
||||
|
||||
" ---------------------------------------------------------------------
|
||||
" vim: ts=8 sts=2 fdm=marker nowrap
|
|
@ -1,113 +0,0 @@
|
|||
" FILE: syntax/conque_term.vim {{{
|
||||
" AUTHOR: Nico Raffo <nicoraffo@gmail.com>
|
||||
" WEBSITE: http://conque.googlecode.com
|
||||
" MODIFIED: 2011-08-12
|
||||
" VERSION: 2.2, for Vim 7.0
|
||||
" LICENSE:
|
||||
" Conque - Vim terminal/console emulator
|
||||
" Copyright (C) 2009-__YEAR__ Nico Raffo
|
||||
"
|
||||
" MIT License
|
||||
"
|
||||
" Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
" of this software and associated documentation files (the "Software"), to deal
|
||||
" in the Software without restriction, including without limitation the rights
|
||||
" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
" copies of the Software, and to permit persons to whom the Software is
|
||||
" furnished to do so, subject to the following conditions:
|
||||
"
|
||||
" The above copyright notice and this permission notice shall be included in
|
||||
" all copies or substantial portions of the Software.
|
||||
"
|
||||
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
" THE SOFTWARE.
|
||||
" }}}
|
||||
|
||||
|
||||
" *******************************************************************************************************************
|
||||
" MySQL *************************************************************************************************************
|
||||
" *******************************************************************************************************************
|
||||
|
||||
" TODO Move these to syntax which is only executed for mysql
|
||||
"syn match MySQLTableBodyG "^\s*\w\+:\(.\+\)\=$" contains=MySQLTableHeadG,MySQLNullG,MySQLBool,MySQLNumberG,MySQLStorageClass oneline skipwhite skipnl
|
||||
"syn match MySQLTableHeadG "^\s*\w\+:" contains=MySQLTableColon skipwhite contained
|
||||
"syn match MySQLTableColon ":" contained
|
||||
|
||||
syn match MySQLTableHead "^ *|.*| *$" nextgroup=MySQLTableDivide contains=MySQLTableBar oneline skipwhite skipnl
|
||||
syn match MySQLTableBody "^ *|.*| *$" nextgroup=MySQLTableBody,MySQLTableEnd contains=MySQLTableBar,MySQLNull,MySQLBool,MySQLNumber,MySQLStorageClass oneline skipwhite skipnl
|
||||
syn match MySQLTableEnd "^ *+[+=-]\++ *$" oneline
|
||||
syn match MySQLTableDivide "^ *+[+=-]\++ *$" nextgroup=MySQLTableBody oneline skipwhite skipnl
|
||||
syn match MySQLTableStart "^ *+[+=-]\++ *$" nextgroup=MySQLTableHead oneline skipwhite skipnl
|
||||
syn match MySQLNull " NULL " contained contains=MySQLTableBar
|
||||
syn match MySQLStorageClass " PRI " contained
|
||||
syn match MySQLStorageClass " MUL " contained
|
||||
syn match MySQLStorageClass " UNI " contained
|
||||
syn match MySQLStorageClass " CURRENT_TIMESTAMP " contained
|
||||
syn match MySQLStorageClass " auto_increment " contained
|
||||
syn match MySQLTableBar "|" contained
|
||||
syn match MySQLNumber "|\? *\d\+\(\.\d\+\)\? *|" contained contains=MySQLTableBar
|
||||
syn match MySQLQueryStat "^\d\+ rows\? in set.*" oneline
|
||||
syn match MySQLPromptLine "^.\?mysql> .*$" contains=MySQLKeyword,MySQLPrompt,MySQLString oneline
|
||||
syn match MySQLPromptLine "^ -> .*$" contains=MySQLKeyword,MySQLPrompt,MySQLString oneline
|
||||
syn match MySQLPrompt "^.\?mysql>" contained oneline
|
||||
syn match MySQLPrompt "^ ->" contained oneline
|
||||
syn case ignore
|
||||
syn keyword MySQLKeyword select count max sum avg date show table tables status like as from left right outer inner join contained
|
||||
syn keyword MySQLKeyword where group by having limit offset order desc asc show contained and interval is null on
|
||||
syn case match
|
||||
syn region MySQLString start=+'+ end=+'+ skip=+\\'+ contained oneline
|
||||
syn region MySQLString start=+"+ end=+"+ skip=+\\"+ contained oneline
|
||||
syn region MySQLString start=+`+ end=+`+ skip=+\\`+ contained oneline
|
||||
|
||||
|
||||
hi def link MySQLPrompt Identifier
|
||||
hi def link MySQLTableHead Title
|
||||
hi def link MySQLTableBody Normal
|
||||
hi def link MySQLBool Boolean
|
||||
hi def link MySQLStorageClass StorageClass
|
||||
hi def link MySQLNumber Number
|
||||
hi def link MySQLKeyword Keyword
|
||||
hi def link MySQLString String
|
||||
|
||||
" terms which have no reasonable default highlight group to link to
|
||||
hi MySQLTableHead term=bold cterm=bold gui=bold
|
||||
if &background == 'dark'
|
||||
hi MySQLTableEnd term=NONE cterm=NONE gui=NONE ctermfg=238 guifg=#444444
|
||||
hi MySQLTableDivide term=NONE cterm=NONE gui=NONE ctermfg=238 guifg=#444444
|
||||
hi MySQLTableStart term=NONE cterm=NONE gui=NONE ctermfg=238 guifg=#444444
|
||||
hi MySQLTableBar term=NONE cterm=NONE gui=NONE ctermfg=238 guifg=#444444
|
||||
hi MySQLNull term=NONE cterm=NONE gui=NONE ctermfg=238 guifg=#444444
|
||||
hi MySQLQueryStat term=NONE cterm=NONE gui=NONE ctermfg=238 guifg=#444444
|
||||
elseif &background == 'light'
|
||||
hi MySQLTableEnd term=NONE cterm=NONE gui=NONE ctermfg=247 guifg=#9e9e9e
|
||||
hi MySQLTableDivide term=NONE cterm=NONE gui=NONE ctermfg=247 guifg=#9e9e9e
|
||||
hi MySQLTableStart term=NONE cterm=NONE gui=NONE ctermfg=247 guifg=#9e9e9e
|
||||
hi MySQLTableBar term=NONE cterm=NONE gui=NONE ctermfg=247 guifg=#9e9e9e
|
||||
hi MySQLNull term=NONE cterm=NONE gui=NONE ctermfg=247 guifg=#9e9e9e
|
||||
hi MySQLQueryStat term=NONE cterm=NONE gui=NONE ctermfg=247 guifg=#9e9e9e
|
||||
endif
|
||||
|
||||
|
||||
" *******************************************************************************************************************
|
||||
" Bash **************************************************************************************************************
|
||||
" *******************************************************************************************************************
|
||||
|
||||
" Typical Prompt
|
||||
if g:ConqueTerm_PromptRegex != ''
|
||||
silent execute "syn match ConquePromptLine '" . g:ConqueTerm_PromptRegex . ".*$' contains=ConquePrompt,ConqueString oneline"
|
||||
silent execute "syn match ConquePrompt '" . g:ConqueTerm_PromptRegex . "' contained oneline"
|
||||
hi def link ConquePrompt Identifier
|
||||
endif
|
||||
|
||||
" Strings
|
||||
syn region ConqueString start=+'+ end=+'+ skip=+\\'+ contained oneline
|
||||
syn region ConqueString start=+"+ end=+"+ skip=+\\"+ contained oneline
|
||||
syn region ConqueString start=+`+ end=+`+ skip=+\\`+ contained oneline
|
||||
hi def link ConqueString String
|
||||
|
||||
" vim: foldmethod=marker
|
3
vimrc
3
vimrc
|
@ -27,6 +27,7 @@ Plugin 'The-NERD-Tree'
|
|||
Plugin 'open-terminal-filemanager'
|
||||
Plugin 'Conque-Shell'
|
||||
Plugin 'taglist-plus'
|
||||
Plugin 'darfink/vim-plist'
|
||||
Plugin 'vcscommand.vim'
|
||||
Plugin 'TextFormat'
|
||||
Plugin 'jsbeautify'
|
||||
|
@ -36,6 +37,7 @@ Plugin 'vim-pandoc/vim-pandoc'
|
|||
Plugin 'vim-pandoc/vim-pandoc-syntax'
|
||||
Plugin 'bling/vim-airline'
|
||||
Plugin 'saltstack/salt-vim'
|
||||
Plugin 'andviro/flake8-vim'
|
||||
|
||||
call vundle#end() " required
|
||||
|
||||
|
@ -56,6 +58,7 @@ set expandtab
|
|||
set softtabstop=4
|
||||
" set autoindent
|
||||
" set smartindent
|
||||
let g:PyFlakeDisabledMessages = 'E128,E501,E116'
|
||||
|
||||
" Highlightinh in python:
|
||||
let python_highlight_numbers = 1
|
||||
|
|
Loading…
Reference in New Issue