# Code comment plugin
# This file is part of gedit
#
# Copyright (C) 2005-2006 Igalia
# Copyright (C) 2006 Matthew Dugan
#
# 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., 59 Temple Place, Suite 330,
# Boston, MA 02111-1307, USA.
import gedit
import gtk
import copy
from gettext import gettext as _
tags_dict = {'text/x-c-header' : ('/* ' , ' */'),
'text/x-chdr' : ('/* ' , ' */'),
'text/x-csrc' : ('/* ' , ' */'), # C comment tags
'text/x-c++hdr' : ("// " , None),
'text/x-c++src' : ("// " , None), # C++ comment tags
'text/x-csharpsrc' : ("// " , None), # C#
'text/x-adasrc' : ("-- " , None), # Ada
'text/x-python' : ("# " , None), # Python comment tags
'text/x-objcsrc' : ("% " , None), # Matlab/Octave
'text/x-fortran' : ("! " , None), # Fortran 95
'text/css' : ("/* " , " */"), # CSS
'text/x-gtkrc' : ("# " , None), # gtkrc
'text/x-haskell' : ("-- " , None), # Haskell
'text/html' : (""), # (X)HTML
'text/x-ini-file' : ("; " , None), # INI
'text/x-java' : ("// " , None), # Java
'text/x-javascript' : ("// " , None), # Javascript
'text/x-tex' : ("% " , None), # Latex
'text/x-lua' : ("# " , None), # LUA
'text/x-makefile' : ("# " , None), # Makefile
'text/x-pascal' : ("(* " , " *)"), # Pascal
'text/x-perl' : ("# " , None), # Perl
'application/x-php' : ("# " , None), # PHP
'application/x-ruby': ("# " , None), # Ruby
'text/x-shellscript': ("# " , None), # Sh
'text/xml' : (""), # XML
}
def forward_tag(iter, tag):
iter.forward_chars(len(tag))
def backward_tag(iter, tag):
iter.backward_chars(len(tag))
def get_tag_position_in_line(tag, head_iter, iter):
found = False
while (not iter.ends_line()) and (not found):
s = iter.get_slice(head_iter)
if s == tag:
found = True
else:
head_iter.forward_char()
iter.forward_char()
return found
def add_comment_characters(document, start_tag, end_tag, start, end):
smark = document.create_mark("start", start, False)
imark = document.create_mark("iter", start, False)
emark = document.create_mark("end", end, False)
number_lines = end.get_line() - start.get_line() + 1
document.begin_user_action()
for i in range(0, number_lines):
iter = document.get_iter_at_mark(imark)
if not iter.ends_line():
document.insert(iter, start_tag, -1)
if end_tag is not None:
if i != number_lines -1:
iter = document.get_iter_at_mark(imark)
iter.forward_to_line_end()
document.insert(iter, end_tag, -1)
else:
iter = document.get_iter_at_mark(emark)
document.insert(iter, end_tag, -1)
iter = document.get_iter_at_mark(imark)
iter.forward_line()
document.delete_mark(imark)
imark = document.create_mark("iter", iter, True)
document.end_user_action()
document.delete_mark(imark)
new_start = document.get_iter_at_mark(smark)
new_end = document.get_iter_at_mark(emark)
if not new_start.ends_line():
backward_tag(new_start, start_tag)
document.select_range(new_start, new_end)
document.delete_mark(smark)
document.delete_mark(emark)
def remove_comment_characters(document, start_tag, end_tag, start, end):
smark = document.create_mark("start", start, False)
emark = document.create_mark("end", end, False)
number_lines = end.get_line() - start.get_line() + 1
iter = start.copy()
head_iter = iter.copy()
forward_tag(head_iter, start_tag)
document.begin_user_action()
for i in range(0, number_lines):
if get_tag_position_in_line(start_tag, head_iter, iter):
dmark = document.create_mark("delete", iter, False)
document.delete(iter, head_iter)
if end_tag is not None:
iter = document.get_iter_at_mark(dmark)
head_iter = iter.copy()
forward_tag(head_iter, end_tag)
if get_tag_position_in_line(end_tag, head_iter, iter):
document.delete(iter, head_iter)
document.delete_mark(dmark)
iter = document.get_iter_at_mark(smark)
iter.forward_line()
document.delete_mark(smark)
head_iter = iter.copy()
forward_tag(head_iter, start_tag)
smark = document.create_mark("iter", iter, True)
document.end_user_action()
document.delete_mark(smark)
document.delete_mark(emark)
def do_comment(document, unindent=False):
selection = document.get_selection_bounds()
currentPosMark = document.get_insert()
deselect = False
if selection != ():
(start, end) = selection
else:
deselect = True
start = document.get_iter_at_mark(currentPosMark)
if start.ends_line():
return
end = start.copy()
if not end.forward_to_line_end():
return
doc_type = document.get_mime_type()
if tags_dict.has_key(doc_type):
(start_tag, end_tag) = tags_dict[doc_type]
if unindent: # Select the comment or the uncomment method
new_code = remove_comment_characters(document,
start_tag,
end_tag,
start,
end)
else:
new_code = add_comment_characters(document,
start_tag,
end_tag,
start,
end)
if deselect:
oldPosIter = document.get_iter_at_mark(currentPosMark)
document.select_range(oldPosIter,oldPosIter)
document.place_cursor(oldPosIter)
ui_str = """
"""
class CodeCommentWindowHelper(object):
def __init__(self, plugin, window):
self._window = window
self._plugin = plugin
self._insert_menu()
def deactivate(self, window):
self._remove_menu()
self._action_group = None
self._window = None
self._plugin = None
def _insert_menu(self):
manager = self._window.get_ui_manager()
self._action_group = gtk.ActionGroup("CodeCommentActions")
self._action_group.add_actions([("CodeComment",
None,
_("Co_mment Code"),
"M",
_("Comment the selected code"),
lambda a, w: do_comment (w.get_active_document())),
('CodeUncomment',
None,
_('U_ncomment Code'),
"M",
_("Uncomment the selected code"),
lambda a, w: do_comment (w.get_active_document(), True))],
self._window)
manager.insert_action_group(self._action_group, -1)
self._ui_id = manager.add_ui_from_string(ui_str)
def _remove_menu(self):
manager = self._window.get_ui_manager()
manager.remove_ui(self._ui_id)
manager.remove_action_group(self._action_group)
manager.ensure_update()
def update_ui(self):
doc = self._window.get_active_document()
if doc:
doc_type = doc.get_mime_type()
self._action_group.set_sensitive(tags_dict.has_key(doc_type))
else:
self._action_group.set_sensitive(False)
class CodeCommentPlugin(gedit.Plugin):
DATA_TAG = "CodeCommentPluginInstance"
def __init__(self):
gedit.Plugin.__init__(self)
def _get_instance(self, window):
return window.get_data(self.DATA_TAG)
def _set_instance(self, window, instance):
window.set_data(self.DATA_TAG, instance)
def activate(self, window):
self._set_instance(window, CodeCommentWindowHelper(self, window))
def deactivate(self, window):
self._get_instance.deactivate()
self._set_instance(window, None)
def update_ui(self, window):
self._get_instance(window).update_ui()