added command completion

This commit is contained in:
elias.bachaalany 2010-07-19 13:00:33 +00:00
parent d76ccd7b1e
commit 97a9805336
5 changed files with 87 additions and 4 deletions

View File

@ -50,7 +50,7 @@ class mycli_t(cli_t):
This callback is optional. This callback is optional.
@param prefix: Line prefix at x (string) @param prefix: Line prefix at prefix_start (string)
@param n: completion number (int) @param n: completion number (int)
@param line: the current line (string) @param line: the current line (string)
@param prefix_start: the index where PREFIX starts in LINE (int) @param prefix_start: the index where PREFIX starts in LINE (int)

View File

@ -1,7 +1,7 @@
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// IDAPython - Python plugin for Interactive Disassembler Pro // IDAPython - Python plugin for Interactive Disassembler Pro
// //
// Copyright (c) 2004-2010 Gergely Erdelyi <gergely.erdelyi@d-dome.net> // Copyright (c) The IDAPython Team <idapython@googlegroups.com>
// //
// All rights reserved. // All rights reserved.
// //
@ -1021,6 +1021,35 @@ bool idaapi IDAPython_cli_execute_line(const char *line)
return true; return true;
} }
//-------------------------------------------------------------------------
bool idaapi IDAPYthon_cli_complete_line(
qstring *completion,
const char *prefix,
int n,
const char *line,
int x)
{
PyObject *py_complete = get_idaapi_attr(S_IDAAPI_COMPLETION);
if ( py_complete == NULL )
return false;
PyObject *py_ret = PyObject_CallFunction(py_complete, "sisi", prefix, n, line, x);
Py_DECREF(py_complete);
// Swallow the error
PyW_GetError(completion);
bool ok = py_ret != NULL && PyString_Check(py_ret) != 0;
if ( ok )
*completion = PyString_AS_STRING(py_ret);
Py_XDECREF(py_ret);
return ok;
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
static const cli_t cli_python = static const cli_t cli_python =
{ {
@ -1030,7 +1059,7 @@ static const cli_t cli_python =
"Python - IDAPython plugin", "Python - IDAPython plugin",
"Enter any Python expression", "Enter any Python expression",
IDAPython_cli_execute_line, IDAPython_cli_execute_line,
NULL, IDAPYthon_cli_complete_line,
NULL NULL
}; };

View File

@ -25,6 +25,7 @@
#define S_IDAAPI_MODNAME "idaapi" #define S_IDAAPI_MODNAME "idaapi"
#define S_IDC_MODNAME "idc" #define S_IDC_MODNAME "idc"
#define S_IDAAPI_EXECSCRIPT "IDAPython_ExecScript" #define S_IDAAPI_EXECSCRIPT "IDAPython_ExecScript"
#define S_IDAAPI_COMPLETION "IDAPython_Completion"
// Vector of PyObject* // Vector of PyObject*
typedef qvector<PyObject *> ppyobject_vec_t; typedef qvector<PyObject *> ppyobject_vec_t;

View File

@ -1635,10 +1635,13 @@ typedef int error_t;
%pythoncode %{ %pythoncode %{
#<pycode(py_idaapi)> #<pycode(py_idaapi)>
import struct import struct
import traceback import traceback
import os import os
import sys import sys
import __builtin__
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# Seek constants # Seek constants
@ -1935,6 +1938,56 @@ def IDAPython_ExecScript(script, g):
return PY_COMPILE_ERR return PY_COMPILE_ERR
# ----------------------------------------------------------------------
class __IDAPython_Completion_Util(object):
"""Internal utility class for auto-completion support"""
def __init__(self):
self.n = 0
self.completion = None
@staticmethod
def parse_identifier(line, prefix, prefix_start):
"""Parse a line and extracts"""
id_start = prefix_start
while id_start > 0:
ch = line[id_start]
if not ch.isalpha() and ch != '.' and ch != '_':
id_start += 1
break
id_start -= 1
return line[id_start:prefix_start + len(prefix)]
@staticmethod
def get_completion(id, prefix):
try:
parts = id.split('.')
m = sys.modules['__main__']
c = len(parts)
for i in xrange(0, c-1):
m = getattr(m, parts[i])
except Exception, e:
return None
else:
# search in the module
completion = [x for x in dir(m) if x.startswith(prefix)]
# no completion found? looking from the global scope? then try the builtins
if not completion and c == 1:
completion = [x for x in dir(__builtin__) if x.startswith(prefix)]
return completion if len(completion) else None
def __call__(self, prefix, n, line, prefix_start):
if n == 0:
self.n = n
id = self.parse_identifier(line, prefix, prefix_start)
self.completion = self.get_completion(id, prefix)
return None if self.completion is None or n >= len(self.completion) else self.completion[n]
IDAPython_Completion = __IDAPython_Completion_Util()
# The general callback format of notify_when() is: # The general callback format of notify_when() is:

View File

@ -2715,7 +2715,7 @@ class cli_t(pyidc_opaque_object_t):
# #
# This callback is optional. # This callback is optional.
# #
# @param prefix: Line prefix at x (string) # @param prefix: Line prefix at prefix_start (string)
# @param n: completion number (int) # @param n: completion number (int)
# @param line: the current line (string) # @param line: the current line (string)
# @param prefix_start: the index where PREFIX starts in LINE (int) # @param prefix_start: the index where PREFIX starts in LINE (int)