diff options
author | flavio <fdanesse@gmail.com> | 2013-05-25 19:42:20 (GMT) |
---|---|---|
committer | flavio <fdanesse@gmail.com> | 2013-05-25 19:43:53 (GMT) |
commit | 561eccbedc21884da59b294cf45cfb2ea0f54375 (patch) | |
tree | 14687494de4c86401d3eebc8b71536aaa4d6bfa5 | |
parent | 4ab968d0aa1cad79ebec9e4d0262f3ad2c28db22 (diff) |
Nuevo sistema de autocompletado
-rw-r--r-- | WorkPanel.py | 251 | ||||
-rw-r--r-- | gtkintrospection.py | 175 |
2 files changed, 301 insertions, 125 deletions
diff --git a/WorkPanel.py b/WorkPanel.py index bfa2713..7238fcd 100644 --- a/WorkPanel.py +++ b/WorkPanel.py @@ -30,6 +30,8 @@ from gi.repository import GtkSource from gi.repository import Vte from gi.repository import GLib +PATH = os.path.dirname(__file__) + class WorkPanel(Gtk.Paned): """ Panel, área de trabajo. @@ -275,149 +277,148 @@ class AutoCompletado(GObject.Object, GtkSource.CompletionProvider): def __init__(self, buffer): GObject.Object.__init__(self) - - self.modulo = None - self.nombre_modulo = '' - self.ultimo_seleccionado = None - self.mods_gi = self.__get_modulos_gi() - - self.priority = 1 + self.buffer = buffer - def do_activate_proposal(self, dato1, dato2): + def __set_imports(self, imports): """ - Cuando se selecciona y clickea - una posible solución + Guarda los datos para importaciones previas, + para calculos de autocompletado. """ - nombre = dato1.get_text() - self.nombre_modulo = self.nombre_modulo + "." + nombre - if not self.modulo: - return - try: - self.ultimo_seleccionado = self.modulo.__getattribute__(nombre) - except: - try: - self.ultimo_seleccionado = self.modulo.__getattr__(nombre) - except: - print "Error al obtener el objeto clickeado." + import shelve - def do_get_name(self): + pathin = os.path.join("/tmp", "shelvein") + + archivo = shelve.open(pathin) + archivo["Lista"] = imports + archivo.close() + + def __get_auto_completado(self): """ - Devuelve el nombre del último - módulo al que se auto-completo + Devuelve la lista de opciones posibles + para auto completar. """ - return self.nombre_modulo + import commands - def do_populate(self, context): + pathin = os.path.join("/tmp", "shelvein") + + pathout = os.path.join(commands.getoutput( + 'python %s %s' % ( + os.path.join(PATH, "gtkintrospection.py"), + pathin))) + + lista = [] + + if os.path.exists(pathout): + ### Obtener lista para autocompletado. + + import shelve + + archivo = shelve.open(pathout) + lista = archivo["Lista"] + archivo.close() + + return lista + + def do_activate_proposal(self, dato1, dato2): """ - Obtiene el texto, se fija sí lo - último introducido es un módulo, en caso - de que así sea, hace 'dir(modulo)' y - hace un menú para auto-completado + Cuando se selecciona y clickea + una posible solución. """ - self.modulo = None - - tema = Gtk.IconTheme.get_default() - icono = tema.load_icon(Gtk.STOCK_DIALOG_INFO, 16, 0) - - inicio = self.buffer.get_start_iter() - ingresado = self.buffer.get_iter_at_mark(self.buffer.get_insert()) - texto = self.buffer.get_text(inicio, ingresado, True) - lineas = texto.splitlines() - - if lineas: - linea = lineas[-1] - else: - linea = '' - - if texto: - pass - else: - return - - if len(linea) >= 2: - dato1 = linea[len(linea)-2:len(linea)] - else: - dato1 = "Ningun modulo" - - try: - dat = linea.find(self.nombre_modulo) - dat1 = len(self.nombre_modulo) - dato_nombre = linea[dat:dat1] - except: - dato_nombre = "" - - if dato1[-1] == "." and dato1 != " ." and dato_nombre == self.nombre_modulo: - tipo = str(type(self.ultimo_seleccionado)) - if "class" in tipo or "module" in tipo or "function" in tipo: - self.resultados = [] - for Resultado in dir(self.ultimo_seleccionado): - self.resultados.append( - GtkSource.CompletionItem.new( - Resultado, - Resultado, - icono, - "Descripción - PygiHack")) - context.add_proposals(self, self.resultados, True) - else: - self.ultimo_seleccionado = None - self.nombre_modulo = None - self.modulo = None - - if ' ' in linea: - modulo = linea.split(' ')[-1] - else: - modulo = linea - - if modulo and modulo[-1] == '.': - mod = '' - - for x in modulo[:-1]: - mod += x - - modulo = mod - self.nombre_modulo = modulo - - if modulo in self.mods_gi: - mod = __import__("gi.repository.%s" % modulo) - self.modulo = mod.importer.modules.get(modulo) - try: - if modulo != 'gtk' and modulo != 'gobject': - self.modulo = __import__(modulo) - except: - pass - - self.resultados = [] - - if self.modulo: - for Resultado in dir(self.modulo): - self.resultados.append( - GtkSource.CompletionItem.new( - Resultado, - Resultado, - icono, - "Descripción - PygiHack")) - context.add_proposals(self, self.resultados, True) + pass - def __get_modulos_gi(self): + def do_get_name(self, coso=None, coso2=None): """ - Devuelve una lista de modulos - de Gobject Introspection [Gi] + Devuelve el nombre del último + módulo al que se auto completó. """ - path_gi = "/usr/lib/girepository-1.0" - modulos_nuevos = [] - if os.path.exists(path_gi): - modulos = os.listdir(path_gi) - for modulo in modulos: - modulo = modulo.replace(".typelib", "") - modulo = modulo.rpartition("-") - modulos_nuevos.append(modulo[0]) - return modulos_nuevos + pass + def do_populate(self, context): + """ + Cuando se producen cambios en el buffer. + + Metodología para autocompletado: + * Importar todos los paquetes y módulos que se están + importando en el archivo sobre el cual estamos auto completando. + * Hacer el auto completado propiamente dicho, trabajando sobre + la línea de código que se está editando. + """ + + ### Iterador de texto sobre el código actual. + textiter = self.buffer.get_iter_at_mark(self.buffer.get_insert())# Gtk.TextIter + + ### indice de linea activa. + indice_de_linea_activa = textiter.get_line() + + ### Texto de la linea activa. + texto_de_linea_en_edicion = textiter.get_slice( + self.buffer.get_iter_at_line(indice_de_linea_activa)) + + ### Si hay un punto en la línea. + if "." in texto_de_linea_en_edicion: + + ### Si el punto está en la última palabra. + if "." in texto_de_linea_en_edicion.split()[-1]: + + ### Auto completado se hace sobre "." + if texto_de_linea_en_edicion.endswith("."): + + palabras = texto_de_linea_en_edicion.split() + + if palabras: + ### Importar paquetes y modulos previos + inicio = self.buffer.get_start_iter() + texto = self.buffer.get_text(inicio, textiter, True) + lineas = texto.splitlines() + + imports = [] + + for linea in lineas: + # FIXME: Analizar mejor los casos como ''', """, etc. + if "import " in linea and not linea.startswith("#") and \ + not linea.startswith("\"") and not linea.startswith("'"): + imports.append(linea) + + ### ['import os', 'import sys', 'from os import path'] + ### Esto es [] si auto completado se hace antes de los imports + + ### Auto completado se hace sobre la última palabra + palabra = palabras[-1] + palabra = palabra.split("(")[-1] # Caso: class Ventana(gtk. + + pals = palabra.split(".")[:-1] + imports.append(pals) # ['import os', 'import sys', 'from os import path', ['gtk', 'gdk', '']] + + ### Guardar en un archivo. + self.__set_imports(imports) + + ### Obtener lista para autocompletado. + lista = self.__get_auto_completado() + + opciones = [] + + for item in lista: + opciones.append(GtkSource.CompletionItem.new(item, + item, None, None)) + + context.add_proposals(self, opciones, True) + + else: + # FIXME: Se está autocompletando. + # Esto debe actualizar la lista de opciones disponibles, + # Filtrando en la lista según el texto escrito por el usuario. + text = texto_de_linea_en_edicion.split(".")[-1] + + else: + context.add_proposals(self, [], True) + + else: + context.add_proposals(self, [], True) class Terminal(Vte.Terminal): diff --git a/gtkintrospection.py b/gtkintrospection.py new file mode 100644 index 0000000..4003762 --- /dev/null +++ b/gtkintrospection.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# gtkintrospection.py por: +# Flavio Danesse <fdanesse@activitycentral.com> +# ActivityCentran + +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import os +import sys +import shelve + +### Obtener los datos para hacer autocompletado. +path = os.path.join(sys.argv[1]) + +archivo = shelve.open(path) +lista = archivo["Lista"] +archivo.close() + +imports = lista[:-1] +linea_activa = lista[-1] + +### Hacer importaciones previas. +modulos = {} + +def append_modulo(name): + """ + Importa un módulo según su nombre y lo + almacena importado. + """ + + # FIXME: Requiere analisis con mayor detenimiento. + try: + if not modulos.get(name, ""): + modulos[name] = __import__(name) + + except: + arch = open("/tmp/log", "w") + arch.write(name) + arch.close() + +def append_modulo_to_prev(name, prev): + """ + Importa un módulo que se encuentra dentro de + un paquete, según su nombre y el nombre + del paquete que lo contiene y lo almacena importado. + """ + + # FIXME: Requiere analisis con mayor detenimiento. + try: + if not modulos.get(prev, ""): + append_modulo(prev) + + modulos[name] = modulos[prev].__getattribute__(name) + + except: + pass + +def append_modulo_to_prev_for_path(path): + """ + Importa los módulos necesarios segun path y lo almacena. + """ + + # FIXME: Requiere analisis con mayor detenimiento. + try: + # FIXME: Esta función Falla con tipos from modulo1.modulo2.modulo3 import modulo4 + items = path.split(".") + + contador = 0 + prev = items[0] + + for item in items: + contador += 1 + + if not contador == len(items): + dos = items[contador] + prev = "%s.%s" % (prev, items[contador]) + + mod = __import__(prev).__dict__[dos] + + if not modulos.get(prev, ""): + modulos[prev] = mod + + except: + pass + +for im in imports: + + ### Caso 1: import os + ### Caso Especial: import os, sys, ... + if not "from " in im and not " *" in im and not " as" in im: + temp_list = im.split()[1:] # quitando "import" y separando los módulos. + + for item in temp_list: + name = item.replace(",", "") # quitando ",". + append_modulo(name) # importar y almacenar. + + ### Caso 1: import os + ### Caso Especial: from os import * + elif "from " in im and " *" in im and not " as" in im: + pass + + ### Caso 2: from os import path + ### Caso Especial: from os import path, chmod, ... + elif "from " in im and not " *" in im and not "." in im and not " as" in im: + temp_list = im.split() + prev = temp_list[1] + temp_list = temp_list[3:] + + for item in temp_list: + name = item.replace(",", "") + append_modulo_to_prev(name, prev) + + ### Caso 2: from os import path + ### Caso Especial: from os import * + elif "from " in im and " *" in im and not "." in im and not " as" in im: + pass # http://stackoverflow.com/questions/2916374/how-to-import-with-import + + ### caso 3: from Coso.Ventana import JAMediaPlayer + ### Caso Especial: from Coso.Ventana.Otro import JAMediaPlayer, OtraCosa, ... + elif "from " in im and not " *" in im and "." in im and not " as" in im: + temp_list = im.split() + prev = temp_list[1] + mod_temp_list = temp_list[3:] + + if len(prev.split(".")) < 3: # FIXME la funcion falla para caso especial + ### Caso Especial: módulos de pygi. + if "gi.repository" in prev: + name = mod_temp_list[0] + mod = __import__("%s.%s" % (prev, name)) + modulos[name] = mod.importer.modules.get(name) + + else: + append_modulo_to_prev_for_path(prev) + + for item in mod_temp_list: + name = item.replace(",", "") + append_modulo_to_prev(name, prev) + +### Importar el o los modulos sobre los que se está haciendo auto completado. +lista = [] + +# FIXME: Requiere análisis de casos especiales. +if len(linea_activa) == 1: + name = linea_activa[0] + #append_modulo(name) + + lista = dir(modulos[name]) + #print dir(modulos[name]) + +''' +for key in modulos.keys(): + print key, modulos[key]''' + +### Guardar la lista para autocompletar. +path = os.path.join("/tmp", "shelveout") + +archivo = shelve.open(path) +archivo["Lista"] = lista +archivo.close() + +print path |