[gedit] Fix environment envoding for snippets
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gedit] Fix environment envoding for snippets
- Date: Mon, 30 Jan 2012 12:20:49 +0000 (UTC)
commit 64b82ea29a95f0b94031e20f43848d831dac8ec6
Author: Jesse van den Kieboom <jessevdk gnome org>
Date: Sat Jan 28 15:05:14 2012 +0100
Fix environment envoding for snippets
The environment for snippets was not correctly
setup. In particular, not all strings were
encoded in utf-8, leading to problems when
for example filenames were not encoded in utf-8
and used in placeholders.
This commit introduces two separate environments,
one with proper encoded utf-8 and one with the
original encoding of all the various strings.
The original encoding environment is used only
for shell placeholders.
plugins/snippets/snippets/document.py | 282 ++++++++++++++++--------------
plugins/snippets/snippets/placeholder.py | 49 +++--
plugins/snippets/snippets/snippet.py | 32 ++--
3 files changed, 197 insertions(+), 166 deletions(-)
---
diff --git a/plugins/snippets/snippets/document.py b/plugins/snippets/snippets/document.py
index 86ddc23..119acae 100644
--- a/plugins/snippets/snippets/document.py
+++ b/plugins/snippets/snippets/document.py
@@ -308,124 +308,190 @@ class Document(GObject.Object, Gedit.ViewActivatable, Signals):
(current, prev) = self.previous_placeholder()
return self.goto_placeholder(current, prev)
+ def string_in_native_doc_encoding(self, buf, s):
+ enc = buf.get_encoding()
+
+ if not enc or enc.get_charset() == 'UTF-8':
+ return s
+
+ try:
+ cv = GLib.convert(s, -1, enc.get_charset(), 'UTF-8')
+ return cv[0]
+ except GLib.GError:
+ pass
+
+ return s
+
def env_get_selected_text(self, buf):
bounds = buf.get_selection_bounds()
if bounds:
- return unicode(buf.get_text(bounds[0], bounds[1], False), 'utf-8')
+ u8 = unicode(buf.get_text(bounds[0], bounds[1], False), 'utf-8')
+
+ return {'utf8': u8, 'noenc': self.string_in_native_doc_encoding(buf, u8)}
else:
- return ''
+ return u''
def env_get_current_word(self, buf):
start, end = buffer_word_boundary(buf)
+ enc = buf.get_encoding()
+
+ u8 = unicode(buf.get_text(start, end, False), 'utf-8')
- return unicode(buf.get_text(start, end, False), 'utf-8')
+ return {'utf8': u8, 'noenc': self.string_in_native_doc_encoding(buf, u8)}
def env_get_current_line(self, buf):
start, end = buffer_line_boundary(buf)
- return unicode(buf.get_text(start, end, False), 'utf-8')
+ u8 = unicode(buf.get_text(start, end, False), 'utf-8')
+
+ return {'utf8': u8, 'noenc': self.string_in_native_doc_encoding(buf, u8)}
def env_get_current_line_number(self, buf):
start, end = buffer_line_boundary(buf)
- return unicode(start.get_line() + 1)
+ return unicode(str(start.get_line() + 1), 'utf-8')
- def env_get_document_uri(self, buf):
- location = buf.get_location()
+ def location_uri_for_env(self, location):
+ if not location:
+ return {'utf8': u'', 'noenc': u''}
+ u8 = unicode(location.get_parse_name(), 'utf-8')
+
+ if location.has_uri_scheme('file'):
+ u8 = "file://" + u8
+
+ return {'utf8': u8, 'noenc': location.get_uri()}
+
+ def location_name_for_env(self, location):
if location:
- return location.get_uri()
- else:
- return ''
+ info = location.query_info("standard::display-name", 0, None)
- def env_get_document_name(self, buf):
- location = buf.get_location()
+ return {'utf8': unicode(info.get_display_name(), 'utf-8'),
+ 'noenc': location.get_basename()}
+ else:
+ return u''
+ def location_scheme_for_env(self, location):
if location:
- return location.get_basename()
+ return unicode(location.get_uri_scheme(), 'utf-8')
else:
- return ''
+ return u''
- def env_get_document_scheme(self, buf):
- location = buf.get_location()
+ def location_path_for_env(self, location):
+ if location and location.has_uri_scheme('file'):
+ return {'utf8': unicode(location.get_parse_name(), 'utf-8'),
+ 'noenc': location.get_path()}
+ else:
+ return u''
+ def location_dir_for_env(self, location):
if location:
- return location.get_uri_scheme()
- else:
- return ''
+ parent = location.get_parent()
- def env_get_document_path(self, buf):
- location = buf.get_location()
+ if parent and parent.has_uri_scheme('file'):
+ return {'utf8': parent.get_parse_name(),
+ 'noenc': parent.get_path()}
- if location and Gedit.utils_location_has_file_scheme(location):
- return location.get_path()
- else:
- return ''
+ return u''
- def env_get_document_dir(self, buf):
- location = buf.get_location()
+ def env_add_for_location(self, environ, location, prefix):
+ parts = {'URI': self.location_uri_for_env,
+ 'NAME': self.location_name_for_env,
+ 'SCHEME': self.location_scheme_for_env,
+ 'PATH': self.location_path_for_env,
+ 'DIR': self.location_dir_for_env}
- if location:
- return location.get_parent().get_path() or ''
- else:
- return ''
+ for k in parts:
+ v = parts[k](location)
+ key = prefix + '_' + k
+
+ if isinstance(v, dict):
+ environ['utf8'][key] = v['utf8']
+ environ['noenc'][key] = v['noenc']
+ else:
+ environ['utf8'][key] = v
+ environ['noenc'][key] = str(v)
+
+ return environ
def env_get_document_type(self, buf):
typ = buf.get_mime_type()
if typ:
- return typ
+ return unicode(typ, 'utf-8')
else:
- return ''
+ return u''
def env_get_documents_uri(self, buf):
toplevel = self.view.get_toplevel()
+ documents_uri = {'utf8': [], 'noenc': []}
+
if isinstance(toplevel, Gedit.Window):
- documents_uri = [doc.get_location().get_uri()
- for doc in toplevel.get_documents()
- if doc.get_location() is not None]
- else:
- documents_uri = []
+ for doc in toplevel.get_documents():
+ r = self.location_uri_for_env(doc.get_location())
+
+ if isinstance(r, dict):
+ documents_uri['utf8'].append(r['utf8'])
+ documents_uri['noenc'].append(r['noenc'])
+ else:
+ documents_uri['utf8'].append(r)
+ documents_uri['noenc'].append(str(r))
- return u' '.join(documents_uri)
+ return {'utf8': u' '.join(documents_uri['utf8']),
+ 'noenc': ' '.join(documents_uri['noenc'])}
def env_get_documents_path(self, buf):
toplevel = self.view.get_toplevel()
+ documents_path = {'utf8': [], 'noenc': []}
+
if isinstance(toplevel, Gedit.Window):
- documents_location = [doc.get_location()
- for doc in toplevel.get_documents()
- if doc.get_location() is not None]
+ for doc in toplevel.get_documents():
+ r = self.location_path_for_env(doc.get_location())
- documents_path = [location.get_path()
- for location in documents_location
- if Gedit.utils_location_has_file_scheme(location)]
- else:
- documents_path = []
+ if isinstance(r, dict):
+ documents_path['utf8'].append(r['utf8'])
+ documents_path['noenc'].append(r['noenc'])
+ else:
+ documents_path['utf8'].append(r)
+ documents_path['noenc'].append(str(r))
- return u' '.join(documents_path)
+ return {'utf8': u' '.join(documents_path['utf8']),
+ 'noenc': ' '.join(documents_path['noenc'])}
- def update_environment(self):
+ def get_environment(self):
buf = self.view.get_buffer()
-
- variables = {'GEDIT_SELECTED_TEXT': self.env_get_selected_text,
- 'GEDIT_CURRENT_WORD': self.env_get_current_word,
- 'GEDIT_CURRENT_LINE': self.env_get_current_line,
- 'GEDIT_CURRENT_LINE_NUMBER': self.env_get_current_line_number,
- 'GEDIT_CURRENT_DOCUMENT_URI': self.env_get_document_uri,
- 'GEDIT_CURRENT_DOCUMENT_NAME': self.env_get_document_name,
- 'GEDIT_CURRENT_DOCUMENT_SCHEME': self.env_get_document_scheme,
- 'GEDIT_CURRENT_DOCUMENT_PATH': self.env_get_document_path,
- 'GEDIT_CURRENT_DOCUMENT_DIR': self.env_get_document_dir,
- 'GEDIT_CURRENT_DOCUMENT_TYPE': self.env_get_document_type,
- 'GEDIT_DOCUMENTS_URI': self.env_get_documents_uri,
- 'GEDIT_DOCUMENTS_PATH': self.env_get_documents_path,
- }
+ environ = {'utf8': {}, 'noenc': {}}
+
+ for k in os.environ:
+ # Get the original environment, as utf-8
+ v = os.environ[k]
+ environ['noenc'][k] = v
+ environ['utf8'][k] = unicode(os.environ[k], 'utf-8')
+
+ variables = {u'GEDIT_SELECTED_TEXT': self.env_get_selected_text,
+ u'GEDIT_CURRENT_WORD': self.env_get_current_word,
+ u'GEDIT_CURRENT_LINE': self.env_get_current_line,
+ u'GEDIT_CURRENT_LINE_NUMBER': self.env_get_current_line_number,
+ u'GEDIT_CURRENT_DOCUMENT_TYPE': self.env_get_document_type,
+ u'GEDIT_DOCUMENTS_URI': self.env_get_documents_uri,
+ u'GEDIT_DOCUMENTS_PATH': self.env_get_documents_path}
for var in variables:
- os.environ[var] = variables[var](buf)
+ v = variables[var](buf)
+
+ if isinstance(v, dict):
+ environ['utf8'][var] = v['utf8']
+ environ['noenc'][var] = v['noenc']
+ else:
+ environ['utf8'][var] = v
+ environ['noenc'][var] = str(v)
+
+ self.env_add_for_location(environ, buf.get_location(), 'GEDIT_CURRENT_DOCUMENT')
+
+ return environ
def uses_current_word(self, snippet):
matches = re.findall('(\\\\*)\\$GEDIT_CURRENT_WORD', snippet['text'])
@@ -445,12 +511,22 @@ class Document(GObject.Object, Gedit.ViewActivatable, Signals):
return False
- def apply_snippet(self, snippet, start = None, end = None):
+ def apply_snippet(self, snippet, start = None, end = None, environ = {}):
if not snippet.valid:
return False
+ # Set environmental variables
+ env = self.get_environment()
+
+ if environ:
+ for k in environ['utf8']:
+ env['utf8'][k] = environ['utf8'][k]
+
+ for k in environ['noenc']:
+ env['noenc'][k] = environ['noenc'][k]
+
buf = self.view.get_buffer()
- s = Snippet(snippet)
+ s = Snippet(snippet, env)
if not start:
start = buf.get_iter_at_mark(buf.get_insert())
@@ -469,9 +545,6 @@ class Document(GObject.Object, Gedit.ViewActivatable, Signals):
# it will be removed
start, end = buffer_line_boundary(buf)
- # Set environmental variables
- self.update_environment()
-
# You know, we could be in an end placeholder
(current, next) = self.next_placeholder()
if current and current.__class__ == PlaceholderEnd:
@@ -770,78 +843,23 @@ class Document(GObject.Object, Gedit.ViewActivatable, Signals):
else:
return components
- def relative_path(self, first, second, mime):
- prot1 = re.match('(^[a-z]+:\/\/|\/)(.*)', first)
- prot2 = re.match('(^[a-z]+:\/\/|\/)(.*)', second)
-
- if not prot1 or not prot2:
- return second
-
- # Different protocols
- if prot1.group(1) != prot2.group(1):
- return second
-
- # Split on backslash
- path1 = self.path_split(prot1.group(2))
- path2 = self.path_split(prot2.group(2))
-
- # Remove as long as common
- while path1 and path2 and path1[0] == path2[0]:
- path1.pop(0)
- path2.pop(0)
-
- # If we need to ../ more than 3 times, then just return
- # the absolute path
- if len(path1) - 1 > 3:
- return second
-
- if mime.startswith('x-directory'):
- # directory, special case
- if not path2:
- result = './'
- else:
- result = '../' * (len(path1) - 1)
- else:
- # Insert ../
- result = '../' * (len(path1) - 1)
-
- if not path2:
- result = os.path.basename(second)
-
- if path2:
- result += os.path.join(*path2)
-
- return result
-
def apply_uri_snippet(self, snippet, mime, uri):
# Remove file scheme
gfile = Gio.file_new_for_uri(uri)
- pathname = ''
- dirname = ''
- ruri = ''
-
- if Gedit.utils_location_has_file_scheme(gfile):
- pathname = gfile.get_path()
- dirname = gfile.get_parent().get_path()
- name = gfile.get_basename()
- scheme = gfile.get_uri_scheme()
+ environ = {'utf8': {'GEDIT_DROP_DOCUMENT_TYPE': unicode(mime, 'utf-8')},
+ 'noenc': {'GEDIT_DROP_DOCUMENT_TYPE': mime}}
- os.environ['GEDIT_DROP_DOCUMENT_URI'] = uri
- os.environ['GEDIT_DROP_DOCUMENT_NAME'] = name
- os.environ['GEDIT_DROP_DOCUMENT_SCHEME'] = scheme
- os.environ['GEDIT_DROP_DOCUMENT_PATH'] = pathname
- os.environ['GEDIT_DROP_DOCUMENT_DIR'] = dirname
- os.environ['GEDIT_DROP_DOCUMENT_TYPE'] = mime
+ self.env_add_for_location(environ, gfile, 'GEDIT_DROP_DOCUMENT')
buf = self.view.get_buffer()
location = buf.get_location()
- if location:
- ruri = location.get_uri()
- relpath = self.relative_path(ruri, uri, mime)
+ relpath = location.get_relative_path(gfile)
- os.environ['GEDIT_DROP_DOCUMENT_RELATIVE_PATH'] = relpath
+ # CHECK: what is the encoding of relpath?
+ environ['utf8']['GEDIT_DROP_DOCUMENT_RELATIVE_PATH'] = unicode(relpath, 'utf-8')
+ environ['noenc']['GEDIT_DROP_DOCUMENT_RELATIVE_PATH'] = relpath
mark = buf.get_mark('gtk_drag_target')
@@ -849,7 +867,7 @@ class Document(GObject.Object, Gedit.ViewActivatable, Signals):
mark = buf.get_insert()
piter = buf.get_iter_at_mark(mark)
- self.apply_snippet(snippet, piter, piter)
+ self.apply_snippet(snippet, piter, piter, environ)
def in_bounds(self, x, y):
rect = self.view.get_visible_rect()
diff --git a/plugins/snippets/snippets/placeholder.py b/plugins/snippets/snippets/placeholder.py
index 2628419..c76e4d8 100644
--- a/plugins/snippets/snippets/placeholder.py
+++ b/plugins/snippets/snippets/placeholder.py
@@ -30,7 +30,7 @@ from substitutionparser import SubstitutionParser
# These are places in a view where the cursor can go and do things
class Placeholder:
- def __init__(self, view, tabstop, defaults, begin):
+ def __init__(self, view, tabstop, environ, defaults, begin):
self.ok = True
self.done = False
self.buf = view.get_buffer()
@@ -42,6 +42,8 @@ class Placeholder:
self.set_default(defaults)
self.prev_contents = self.default
self.set_mark_gravity()
+ self.environ = environ
+ self.envkey = 'utf8'
if begin:
self.begin = self.buf.create_mark(None, begin, self.mark_gravity[0])
@@ -50,6 +52,9 @@ class Placeholder:
self.end = None
+ def get_environ(self):
+ return self.environ[self.envkey]
+
def __str__(self):
return '%s (%s)' % (str(self.__class__), str(self.default))
@@ -75,7 +80,6 @@ class Placeholder:
if dm != d:
break
-
def literal(self, s):
return repr(s)
@@ -83,10 +87,12 @@ class Placeholder:
return s
def re_environment(self, m):
- if m.group(1) or not m.group(2) in os.environ:
+ env = self.get_environ()
+
+ if m.group(1) or not m.group(2) in env:
return '$' + m.group(2)
else:
- return self.format_environment(os.environ[m.group(2)])
+ return self.format_environment(env[m.group(2)])
def expand_environment(self, text):
if not text:
@@ -216,8 +222,8 @@ class Placeholder:
# This is an placeholder which inserts a mirror of another Placeholder
class PlaceholderMirror(Placeholder):
- def __init__(self, view, tabstop, begin):
- Placeholder.__init__(self, view, -1, None, begin)
+ def __init__(self, view, tabstop, environ, begin):
+ Placeholder.__init__(self, view, -1, environ, None, begin)
self.mirror_stop = tabstop
def update(self, mirror):
@@ -239,8 +245,8 @@ class PlaceholderMirror(Placeholder):
# This placeholder indicates the end of a snippet
class PlaceholderEnd(Placeholder):
- def __init__(self, view, begin, default):
- Placeholder.__init__(self, view, 0, default, begin)
+ def __init__(self, view, environ, begin, default):
+ Placeholder.__init__(self, view, 0, environ, default, begin)
def run_last(self, placeholders):
Placeholder.run_last(self, placeholders)
@@ -266,8 +272,8 @@ class PlaceholderEnd(Placeholder):
# This placeholder is used to expand a command with embedded mirrors
class PlaceholderExpand(Placeholder):
- def __init__(self, view, tabstop, begin, s):
- Placeholder.__init__(self, view, tabstop, None, begin)
+ def __init__(self, view, tabstop, environ, begin, s):
+ Placeholder.__init__(self, view, tabstop, environ, None, begin)
self.mirror_text = {0: ''}
self.timeout_id = None
@@ -381,11 +387,12 @@ class PlaceholderExpand(Placeholder):
# The shell placeholder executes commands in a subshell
class PlaceholderShell(PlaceholderExpand):
- def __init__(self, view, tabstop, begin, s):
- PlaceholderExpand.__init__(self, view, tabstop, begin, s)
+ def __init__(self, view, tabstop, environ, begin, s):
+ PlaceholderExpand.__init__(self, view, tabstop, environ, begin, s)
self.shell = None
self.remove_me = False
+ self.envkey = 'noenc'
def close_shell(self):
self.shell.stdout.close()
@@ -456,9 +463,9 @@ class PlaceholderShell(PlaceholderExpand):
self.close_shell()
popen_args = {
- 'cwd' : None,
+ 'cwd': None,
'shell': True,
- 'env' : os.environ,
+ 'env': self.get_environ(),
'stdout': subprocess.PIPE
}
@@ -493,8 +500,8 @@ class TimeoutError(Exception):
# The python placeholder evaluates commands in python
class PlaceholderEval(PlaceholderExpand):
- def __init__(self, view, tabstop, refs, begin, s, namespace):
- PlaceholderExpand.__init__(self, view, tabstop, begin, s)
+ def __init__(self, view, tabstop, environ, refs, begin, s, namespace):
+ PlaceholderExpand.__init__(self, view, tabstop, environ, begin, s)
self.fdread = 0
self.remove_me = False
@@ -614,8 +621,8 @@ class PlaceholderEval(PlaceholderExpand):
# Regular expression placeholder
class PlaceholderRegex(PlaceholderExpand):
- def __init__(self, view, tabstop, begin, inp, pattern, substitution, modifiers):
- PlaceholderExpand.__init__(self, view, tabstop, begin, '')
+ def __init__(self, view, tabstop, environ, begin, inp, pattern, substitution, modifiers):
+ PlaceholderExpand.__init__(self, view, tabstop, environ, begin, '')
self.instant_update = True
self.inp = inp
@@ -654,10 +661,12 @@ class PlaceholderRegex(PlaceholderExpand):
return re.escape(s)
def get_input(self):
+ env = self.get_environ()
+
if isinstance(self.inp, int):
return self.mirror_text[self.inp]
- elif self.inp in os.environ:
- return os.environ[self.inp]
+ elif self.inp in env:
+ return env[self.inp]
else:
return ''
diff --git a/plugins/snippets/snippets/snippet.py b/plugins/snippets/snippets/snippet.py
index 1269efd..b8f5a33 100644
--- a/plugins/snippets/snippets/snippet.py
+++ b/plugins/snippets/snippets/snippet.py
@@ -98,8 +98,9 @@ class EvalUtilities:
return result
class Snippet:
- def __init__(self, data):
+ def __init__(self, data, environ = {}):
self.data = data
+ self.environ = environ
def __getitem__(self, prop):
return self.data[prop]
@@ -156,7 +157,10 @@ class Snippet:
return self._view.get_buffer().get_iter_at_mark(self._insert_mark)
def _create_environment(self, data):
- val = ((data in os.environ) and os.environ[data]) or ''
+ if data in self.environ['utf8']:
+ val = self.environ['utf8'][data]
+ else:
+ val = u''
# Get all the current indentation
all_indent = compute_indentation(self._view, self._insert_iter())
@@ -173,25 +177,25 @@ class Snippet:
if tabstop == 0:
# End placeholder
- return PlaceholderEnd(self._view, begin, data['default'])
+ return PlaceholderEnd(self._view, self.environ, begin, data['default'])
elif tabstop in self.placeholders:
# Mirror placeholder
- return PlaceholderMirror(self._view, tabstop, begin)
+ return PlaceholderMirror(self._view, tabstop, self.environ, begin)
else:
# Default placeholder
- return Placeholder(self._view, tabstop, data['default'], begin)
+ return Placeholder(self._view, tabstop, self.environ, data['default'], begin)
def _create_shell(self, data):
begin = self._insert_iter()
- return PlaceholderShell(self._view, data['tabstop'], begin, data['contents'])
+ return PlaceholderShell(self._view, data['tabstop'], self.environ, begin, data['contents'])
def _create_eval(self, data):
begin = self._insert_iter()
- return PlaceholderEval(self._view, data['tabstop'], data['dependencies'], begin, data['contents'], self._utils.namespace)
+ return PlaceholderEval(self._view, data['tabstop'], self.environ, data['dependencies'], begin, data['contents'], self._utils.namespace)
def _create_regex(self, data):
begin = self._insert_iter()
- return PlaceholderRegex(self._view, data['tabstop'], begin, data['input'], data['pattern'], data['substitution'], data['modifiers'])
+ return PlaceholderRegex(self._view, data['tabstop'], self.environ, begin, data['input'], data['pattern'], data['substitution'], data['modifiers'])
def _create_text(self, data):
return data
@@ -234,11 +238,11 @@ class Snippet:
try:
val = {'environment': self._create_environment,
- 'placeholder': self._create_placeholder,
- 'shell': self._create_shell,
- 'eval': self._create_eval,
- 'regex': self._create_regex,
- 'text': self._create_text}[token.klass](token.data)
+ 'placeholder': self._create_placeholder,
+ 'shell': self._create_shell,
+ 'eval': self._create_eval,
+ 'regex': self._create_regex,
+ 'text': self._create_text}[token.klass](token.data)
except:
sys.stderr.write('Token class not supported: %s\n' % token.klass)
continue
@@ -252,7 +256,7 @@ class Snippet:
# Create end placeholder if there isn't one yet
if 0 not in self.placeholders:
- self.placeholders[0] = PlaceholderEnd(self._view, self.end_iter(), None)
+ self.placeholders[0] = PlaceholderEnd(self._view, self.environ, self.end_iter(), None)
self.plugin_data.ordered_placeholders.append(self.placeholders[0])
# Make sure run_last is ran for all placeholders and remove any
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]