shadowbrokers-exploits/windows/fuzzbunch/pyreadline/lineeditor/history.py
2017-04-14 11:45:07 +02:00

245 lines
9.7 KiB
Python

# -*- coding: utf-8 -*-
#*****************************************************************************
# Copyright (C) 2006 Jorgen Stenarson. <jorgen.stenarson@bostream.nu>
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#*****************************************************************************
import re,operator,string,sys,os
#import wordmatcher
#import pyreadline.clipboard as clipboard
if "pyreadline" in sys.modules:
pyreadline= sys.modules["pyreadline"]
else:
import pyreadline
import lineobj
import exceptions
class EscapeHistory(exceptions.Exception):
pass
from pyreadline.logger import log_sock
class LineHistory(object):
def __init__(self):
self.history=[]
self._history_length=100
self._history_cursor=0
self.history_filename=os.path.expanduser('~/.history')
self.lastcommand=None
self.query=""
def get_history_length(self):
value=self._history_length
log_sock("get_history_length:%d"%value,"history")
return value
def set_history_length(self,value):
log_sock("set_history_length: old:%d new:%d"%(self._history_length,value),"history")
self._history_length=value
def get_history_cursor(self):
value=self._history_cursor
log_sock("get_history_cursor:%d"%value,"history")
return value
def set_history_cursor(self,value):
log_sock("set_history_cursor: old:%d new:%d"%(self._history_cursor,value),"history")
self._history_cursor=value
history_length=property(get_history_length,set_history_length)
history_cursor=property(get_history_cursor,set_history_cursor)
def clear_history(self):
'''Clear readline history.'''
self.history[:] = []
self.history_cursor = 0
def read_history_file(self, filename=None):
'''Load a readline history file.'''
if filename is None:
filename=self.history_filename
try:
for line in open(filename, 'r'):
self.add_history(lineobj.ReadLineTextBuffer(line.rstrip()))
except IOError:
self.history = []
self.history_cursor = 0
def write_history_file(self, filename=None):
'''Save a readline history file.'''
if filename is None:
filename=self.history_filename
fp = open(filename, 'wb')
for line in self.history[-self.history_length:]:
fp.write(line.get_line_text())
fp.write('\n')
fp.close()
def add_history(self, line):
'''Append a line to the history buffer, as if it was the last line typed.'''
if not line.get_line_text():
pass
elif len(self.history) > 0 and self.history[-1].get_line_text() == line.get_line_text():
pass
else:
self.history.append(line)
self.history_cursor = len(self.history)
def previous_history(self,current): # (C-p)
'''Move back through the history list, fetching the previous command. '''
if self.history_cursor==len(self.history):
self.history.append(current.copy()) #do not use add_history since we do not want to increment cursor
if self.history_cursor > 0:
self.history_cursor -= 1
current.set_line(self.history[self.history_cursor].get_line_text())
current.point=lineobj.EndOfLine
def next_history(self,current): # (C-n)
'''Move forward through the history list, fetching the next command. '''
if self.history_cursor < len(self.history)-1:
self.history_cursor += 1
current.set_line(self.history[self.history_cursor].get_line_text())
def beginning_of_history(self): # (M-<)
'''Move to the first line in the history.'''
self.history_cursor = 0
if len(self.history) > 0:
self.l_buffer = self.history[0]
def end_of_history(self,current): # (M->)
'''Move to the end of the input history, i.e., the line currently
being entered.'''
self.history_cursor=len(self.history)
current.set_line(self.history[-1].get_line_text())
def reverse_search_history(self,searchfor,startpos=None):
if startpos is None:
startpos=self.history_cursor
res=[(idx,line) for idx,line in enumerate(self.history[startpos:0:-1]) if line.startswith(searchfor)]
if res:
self.history_cursor-=res[0][0]
return res[0][1].get_line_text()
return ""
def forward_search_history(self,searchfor,startpos=None):
if startpos is None:
startpos=self.history_cursor
res=[(idx,line) for idx,line in enumerate(self.history[startpos:]) if line.startswith(searchfor)]
if res:
self.history_cursor+=res[0][0]
return res[0][1].get_line_text()
return ""
def _non_i_search(self, direction, current):
c = pyreadline.rl.console
line = current.get_line_text()
query = ''
while 1:
c.pos(*pyreadline.rl.prompt_end_pos)
scroll = c.write_scrolling(":%s" % query)
pyreadline.rl._update_prompt_pos(scroll)
pyreadline.rl._clear_after()
event = c.getkeypress()
log_sock(str(event),"history")
if event.keyinfo.keyname == 'backspace':
if len(query) > 0:
query = query[:-1]
else:
break
elif event.char in string.letters + string.digits + string.punctuation + ' ':
query += event.char
elif event.keyinfo.keyname == 'return':
break
else:
pyreadline.rl._bell()
log_sock(query,"history")
res=""
if query:
if direction==-1:
res=self.reverse_search_history(query)
else:
res=self.forward_search_history(query)
log_sock(res,"history")
return lineobj.ReadLineTextBuffer(res,point=0)
def non_incremental_reverse_search_history(self,current): # (M-p)
'''Search backward starting at the current line and moving up
through the history as necessary using a non-incremental search for
a string supplied by the user.'''
return self._non_i_search(-1,current)
def non_incremental_forward_search_history(self,current): # (M-n)
'''Search forward starting at the current line and moving down
through the the history as necessary using a non-incremental search
for a string supplied by the user.'''
return self._non_i_search(1,current)
def _search(self, direction, partial):
try:
if (self.lastcommand != self.history_search_forward and
self.lastcommand != self.history_search_backward):
self.query = ''.join(partial[0:partial.point].get_line_text())
hcstart=max(self.history_cursor,0)
log_sock("hcstart %s"%hcstart,"history")
hc = self.history_cursor + direction
while (direction < 0 and hc >= 0) or (direction > 0 and hc < len(self.history)):
h = self.history[hc]
if not self.query:
self.history_cursor = hc
result=lineobj.ReadLineTextBuffer(h,point=len(h.get_line_text()))
return result
elif h.get_line_text().startswith(self.query) and h != partial.get_line_text():
self.history_cursor = hc
result=lineobj.ReadLineTextBuffer(h,point=partial.point)
return result
hc += direction
else:
if len(self.history)==0:
pass
elif hc>=len(self.history) and not self.query:
self.history_cursor=len(self.history)
return lineobj.ReadLineTextBuffer("",point=0)
elif self.history[max(min(hcstart,len(self.history)-1),0)].get_line_text().startswith(self.query) and self.query:
return lineobj.ReadLineTextBuffer(self.history[max(min(hcstart,len(self.history)-1),0)],point=partial.point)
else:
return lineobj.ReadLineTextBuffer(partial,point=partial.point)
return lineobj.ReadLineTextBuffer(self.query,point=min(len(self.query),partial.point))
except IndexError:
log_sock("hcstart:%s %s"%(hcstart,len(self.history)),"history")
raise
def history_search_forward(self,partial): # ()
'''Search forward through the history for the string of characters
between the start of the current line and the point. This is a
non-incremental search. By default, this command is unbound.'''
q= self._search(1,partial)
return q
def history_search_backward(self,partial): # ()
'''Search backward through the history for the string of characters
between the start of the current line and the point. This is a
non-incremental search. By default, this command is unbound.'''
q= self._search(-1,partial)
return q
if __name__=="__main__":
q=LineHistory()
RL=lineobj.ReadLineTextBuffer
q.add_history(RL("aaaa"))
q.add_history(RL("aaba"))
q.add_history(RL("aaca"))
q.add_history(RL("akca"))
q.add_history(RL("bbb"))
q.add_history(RL("ako"))