GTK EntryCompletion by insertion instead of replacement - autocomplete

I've built a GTK application with autocompletion in an Entry, but I'd like the selected "completion" string to be replace the only word that the cursor touches, whereas it currently replaces all text in the Entry.
I can use set_match_func on the EntryCompletion to deliver matches based on only the word that is adjacent to the cursor, but I don't see how to override the text-insertion behaviour. Is there a way for me to do this?
I'm working in Ruby with gtk3. (I linked the doc for gtk2 because for the life of me, I can't find a complete doc for gtk3 in Ruby.)
Edit Here's my implementation (in Ruby), which lacks the desired "insert" behaviour:
module MyAutocomplete
# Add autocomplete to a Gtk::Entry object
def self.add entry, &block
model = Gtk::ListStore.new String
model.append.set_value 0, 'sd'
model.append.set_value 0, 'foo'
model.append.set_value 0, 'six'
completion = Gtk::EntryCompletion.new
completion.set_minimum_key_length 0
completion.set_text_column 0
completion.set_inline_completion true
completion.set_model model
completion.set_match_func do |*args|
self.match_func *args
end
yield(model, completion) if block_given?
entry.set_completion completion
end
def self.match_func(entry_completion, entry_value, list_obj)
len = 0 # Counts characters into the entry text
cursor = entry_completion.entry.position
entry_text = entry_completion.entry.text
entry_tokens = entry_text.scan(/[\w+#]+|[^\w#]+/)
current_token = entry_tokens.find { |tok|
(len += tok.length) >= cursor && tok =~ /\w/
}
obj_text = list_obj.get_value(0)
return current_token && obj_text.start_with?(current_token)
end
end

Related

vscode API: get Position of last character of line

Following up on this still unanswered question regarding VS Code Extensions with the VS Code API. I didn't answer it because it specifically asked for a solution using the with method of the Position object. I couldn't make that work, nor was I able to loop through the object to get the last character. Trying to manipulate the selection with vscode.commands.executeCommand didn't work either, because vscode.window.activeTextEditor doesn't appear to reflect the actual selection in the window as soon as the Execution Development Host starts running. The only solution I could find was the hoop-jumping exercise below, which gets the first character of one line and the first character of the next line, sets a Range, gets the text of that Range, then reduces the length of that text string by 1 to get the last character of the previous line.
function getCursorPosition() {
const position = editor.selection.active;
curPos = selection.start;
return curPos;
}
curPos = getCursorPosition();
var curLineStart = new vscode.Position(curPos.line, 0);
var nextLineStart = new vscode.Position(curPos.line + 1, 0);
var rangeWithFirstCharOfNextLine = new vscode.Range( curLineStart, nextLineStart);
var contentWithFirstCharOfNextLine = editor.document.getText(rangeWithFirstCharOfNextLine);
var firstLineLength = contentWithFirstCharOfNextLine.length - 1;
var curLinePos = new vscode.Position(curPos.line, firstLineLength);
var curLineEndPos = curLinePos.character;
console.log('curLineEndPos :>> ' + curLineEndPos);
I'm obviously missing something - it can't be impossible to get the last character of a line using the VSCode API without mickey-mousing the thing like this. So the question is simply, what is the right way to do this?
Once you have the cursor Position the TextDocument.lineAt() function returns a TextLine. From which you can get its range and that range.end.character will give you the character number of the last character. - not including the linebreak which if you want to include that see TextLine.rangeIncludingLineBreak().
const editor = vscode.window.activeTextEditor;
const document = editor.document;
const cursorPos = editor.selection.active;
document.lineAt(cursorPos).range.end.character;
Note (from [TextDocument.lineAt documentation][1] ):
Returns a text line denoted by the position. Note that the returned
object is not live and changes to the document are not reflected.

how to read a multiline element from PySimpleGUI

My program stub looks like this:
import PySimpleGUI as sg
layout = [[sg.Text("Geheime Nachricht eintippen:")],
[sg.Multiline(size=(70,4),key="GEHEIM")],
[sg.Spin([i for i in range(1,26)], initial_value=12, key="SS"), sg.Text("Schlüssel zwischen 1 und 25 wählen")],
[sg.Radio("Codieren:", "RADIO1", key="XX" ,default=True),
sg.Radio("Decodieren:","RADIO1", key="YY")],
[sg.Text("ERGEBNIS:")],
[sg.Multiline(size=(70,4),key="AUSGABE")],
[sg.Button("Weiter"), sg.Button("Ende")]]
window = sg.Window("Geheimcode", layout)
while True: # Ereignisschleife
event, values = window.Read()
geheimertext = values("GEHEIM")
print(values("GEHEIM"))
schluessel = int(values["SS"])
print ("Schlüssel = ", schluessel)
if values["XX"] == True:
codedecode = "C"
print("wir codieren:",codedecode)
else:
codedecode = "D"
print("wir decodieren:",codedecode)
if event is None or event == "Ende":
break
window.Close()
The program-line geheimertext = values("GEHEIM") gives this error:
TypeError: 'dict' object is not callable
I quess that the multiline generates a dictonary in the dictionary values?
so my simple newbie-question is how to read the multiline of a gui made with pysimpleGUI
ok, one possible solution is to iterate over the elements of the multiline:
geheimertext=""
for zeichen in values["GEHEIM"]:
geheimertext = geheimertext +zeichen
print(geheimertext)
Is there a better solution? Please teach a newbie
print(values["GEHEIM"])
values is a dict, and not a callable, so you cannot use () brackets (callables are functions or objects that have a function property). You can access to values through [] brackets. values["GEHEIM"].

How to filter a GTK tree view that uses a TreeStore (and not a ListStore)?

I am using a Gtk.TreeView with a Gtk.TreeStore as a model for hierarchical data. As an example, let's take a music database organized into three levels: artist/album/title. I would like to filter this tree using a textual search field. For example, typing "Five" into the search field should give a result along the path "Hank Marvin/Heartbeat/Take Five".
My understanding is that I need to create a callback function and register it using Gtk.TreeModelFilter.set_visible_func(). The problem is that making the line for "Take Five" visible is not enough to make it appear, I also have to set all of its parents visible as well. However, that would require me to traverse the tree up to its root and actively make each node visible along that path, which does not fit into the callback pattern.
One way I see to make this logic work with the callback pattern is to check the whole subtree in the callback function, but that way each leaf node would get checked three times. Even though the performance penalty would be acceptable with such a shallow tree, this hack gives me the goosebumps and I would like to refrain from using it:
def visible_callback(self, model, iter, _data=None):
search_query = self.entry.get_text().lower()
if search_query == "":
return True
text = model.get_value(iter, 0).lower()
if search_query in text:
return True
# Horrible hack
for i in range(model.iter_n_children(iter)):
if self.visible_callback(model, model.iter_nth_child(iter, i)):
return True
return False
What is the intended way to filter a tree view in GTK? (My example is written in Python, but a solution for any language binding of GTK would be fine.)
Finally I came up with a solution and since I haven't found any treeview filtering examples on the internet that uses a TreeStore and not a ListStore, I'm posting my solution here as an example:
#! /usr/bin/python
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Pango', '1.0')
from gi.repository import Gtk
from gi.repository import Pango
from gi.repository import GLib
import signal
HIERARCHICAL_DATA = {
"Queen": {
"A Kind of Magic": [ "Who Wants to Live Forever", "A Kind of Magic" ],
"The Miracle": [ "Breakthru", "Scandal" ]
},
"Five Finger Death Punch": {
"The Way of the Fist": [ "The Way of the Fist", "The Bleeding" ],
},
"Hank Marvin": {
"Heartbeat": [ "Oxygene (Part IV)", "Take Five" ]
}
}
ICONS = [ "stock_people", "media-optical", "sound" ]
class TreeViewFilteringDemo(Gtk.Window):
EXPAND_BY_DEFAULT = True
SPACING = 10
# Controls whether the row should be visible
COL_VISIBLE = 0
# Text to be displayed
COL_TEXT = 1
# Desired weight of the text (bold for matching rows)
COL_WEIGHT = 2
# Icon to be displayed
COL_ICON = 3
def __init__(self):
# Set up window
Gtk.Window.__init__(self, title="TreeView filtering demo")
self.set_size_request(500, 500)
self.set_position(Gtk.WindowPosition.CENTER)
self.set_resizable(True)
self.set_border_width(self.SPACING)
# Set up and populate a tree store
self.tree_store = Gtk.TreeStore(bool, str, Pango.Weight, str)
self.add_nodes(HIERARCHICAL_DATA, None, 0)
# Create some boxes for laying out the different controls
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=self.SPACING)
vbox.set_homogeneous(False)
hbox = Gtk.Box(Gtk.Orientation.HORIZONTAL, spacing=self.SPACING)
hbox.set_homogeneous(False)
vbox.pack_start(hbox, False, True, 0)
self.add(vbox)
# A text entry for filtering
self.search_entry = Gtk.Entry()
self.search_entry.set_placeholder_text("Enter text here to filter results")
self.search_entry.connect("changed", self.refresh_results)
hbox.pack_start(self.search_entry, True, True, 0)
# Add a checkbox for controlling subtree display
self.subtree_checkbox = Gtk.CheckButton("Show subtrees of matches")
self.subtree_checkbox.connect("toggled", self.refresh_results)
hbox.pack_start(self.subtree_checkbox, False, False, 0)
# Use an internal column for filtering
self.filter = self.tree_store.filter_new()
self.filter.set_visible_column(self.COL_VISIBLE)
self.treeview = Gtk.TreeView(model=self.filter)
# CellRenderers for icons and texts
icon_renderer = Gtk.CellRendererPixbuf()
text_renderer = Gtk.CellRendererText()
# Put the icon and the text into a single column (otherwise only the
# first column would be indented according to its depth in the tree)
col_combined = Gtk.TreeViewColumn("Icon and Text")
col_combined.pack_start(icon_renderer, False)
col_combined.pack_start(text_renderer, False)
col_combined.add_attribute(text_renderer, "text", self.COL_TEXT)
col_combined.add_attribute(text_renderer, "weight", self.COL_WEIGHT)
col_combined.add_attribute(icon_renderer, "icon_name", self.COL_ICON)
self.treeview.append_column(col_combined)
# Scrolled Window in case results don't fit in the available space
self.sw = Gtk.ScrolledWindow()
self.sw.add(self.treeview)
vbox.pack_start(self.sw, True, True, 0)
# Initialize filtering
self.refresh_results()
def add_nodes(self, data, parent, level):
"Create the tree nodes from a hierarchical data structure"
if isinstance(data, dict):
for key, value in data.items():
child = self.tree_store.append(parent, [True, key, Pango.Weight.NORMAL, ICONS[level]])
self.add_nodes(value, child, level + 1)
else:
for text in data:
self.tree_store.append(parent, [True, text, Pango.Weight.NORMAL, ICONS[level]])
def refresh_results(self, _widget = None):
"Apply filtering to results"
search_query = self.search_entry.get_text().lower()
show_subtrees_of_matches = self.subtree_checkbox.get_active()
if search_query == "":
self.tree_store.foreach(self.reset_row, True)
if self.EXPAND_BY_DEFAULT:
self.treeview.expand_all()
else:
self.treeview.collapse_all()
else:
self.tree_store.foreach(self.reset_row, False)
self.tree_store.foreach(self.show_matches, search_query, show_subtrees_of_matches)
self.treeview.expand_all()
self.filter.refilter()
def reset_row(self, model, path, iter, make_visible):
"Reset some row attributes independent of row hierarchy"
self.tree_store.set_value(iter, self.COL_WEIGHT, Pango.Weight.NORMAL)
self.tree_store.set_value(iter, self.COL_VISIBLE, make_visible)
def make_path_visible(self, model, iter):
"Make a row and its ancestors visible"
while iter:
self.tree_store.set_value(iter, self.COL_VISIBLE, True)
iter = model.iter_parent(iter)
def make_subtree_visible(self, model, iter):
"Make descendants of a row visible"
for i in range(model.iter_n_children(iter)):
subtree = model.iter_nth_child(iter, i)
if model.get_value(subtree, self.COL_VISIBLE):
# Subtree already visible
continue
self.tree_store.set_value(subtree, self.COL_VISIBLE, True)
self.make_subtree_visible(model, subtree)
def show_matches(self, model, path, iter, search_query, show_subtrees_of_matches):
text = model.get_value(iter, self.COL_TEXT).lower()
if search_query in text:
# Highlight direct match with bold
self.tree_store.set_value(iter, self.COL_WEIGHT, Pango.Weight.BOLD)
# Propagate visibility change up
self.make_path_visible(model, iter)
if show_subtrees_of_matches:
# Propagate visibility change down
self.make_subtree_visible(model, iter)
return
win = TreeViewFilteringDemo()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
# Make sure that the application can be stopped from the terminal using Ctrl-C
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, Gtk.main_quit)
Gtk.main()

Doxygen #code line numbers

Is there a way to display code line numbers inside a #code ... #endcode block? From the screenshots in the doxygen manual it would seem that there is, but I was unable to find an option for doxygen itself, or a tag syntax to accomplish this.
I need this to be able to write something like "In the above code, line 3" after a code block.
Tested also for fenced code blocks, still getting no numbers.
Short Answer
It seems that at least in the current version (1.8.9) line numbers are added:
to C code only when using \includelineno tag
to any Python code
Details
Python code formatter
Python code formatter includes line numbers if g_sourceFileDef evaluates as TRUE:
/*! start a new line of code, inserting a line number if g_sourceFileDef
* is TRUE. If a definition starts at the current line, then the line
* number is linked to the documentation of that definition.
*/
static void startCodeLine()
{
//if (g_currentFontClass) { g_code->endFontClass(); }
if (g_sourceFileDef)
( https://github.com/doxygen/doxygen/blob/Release_1_8_9/src/pycode.l#L356
)
It's initialized from FileDef *fd passed into parseCode/parsePythonCode if it was provided (non-zero) or from new FileDef(<...>) otherwise:
g_sourceFileDef = fd;
<...>
if (fd==0)
{
// create a dummy filedef for the example
g_sourceFileDef = new FileDef("",(exName?exName:"generated"));
cleanupSourceDef = TRUE;
}
( https://github.com/doxygen/doxygen/blob/Release_1_8_9/src/pycode.l#L1458 )
so it seems all Python code is having line numbers included
C code formatter
C code formatter has an additional variable g_lineNumbers and includes line numbers if both g_sourceFileDef and g_lineNumbers evaluate as TRUE:
/*! start a new line of code, inserting a line number if g_sourceFileDef
* is TRUE. If a definition starts at the current line, then the line
* number is linked to the documentation of that definition.
*/
static void startCodeLine()
{
//if (g_currentFontClass) { g_code->endFontClass(); }
if (g_sourceFileDef && g_lineNumbers)
( https://github.com/doxygen/doxygen/blob/Release_1_8_9/src/code.l#L486 )
They are initialized in the following way:
g_sourceFileDef = fd;
g_lineNumbers = fd!=0 && showLineNumbers;
<...>
if (fd==0)
{
// create a dummy filedef for the example
g_sourceFileDef = new FileDef("",(exName?exName:"generated"));
cleanupSourceDef = TRUE;
}
( https://github.com/doxygen/doxygen/blob/Release_1_8_9/src/code.l#L3623 )
Note that g_lineNumbers remains FALSE if provided fd value was 0
HtmlDocVisitor
Among parseCode calls in HtmlDocVisitor::visit there is only one (for DocInclude::IncWithLines, what corresponds to \includelineno) which passes non-zero fd:
https://github.com/doxygen/doxygen/blob/Release_1_8_9/src/htmldocvisitor.cpp#L540
so this seems to be the only command which will result in line numbers included into C code listing

Is there a quick way to add gettext() calls to strings in PyDev?

Is there a quick way to add a gettext() call to a literal string in the PyDev editor running under Eclipse? I.e. when I place the cursor on any literal 'string' in a Python file, I want to turn this into _('string') with a single keypress. Can I use macros or something like that to add such functions?
It should be possible to do that with some simple Python scripting inside PyDev.
Take a look at: http://pydev.org/manual_articles_scripting.html (you can use https://github.com/aptana/Pydev/blob/master/plugins/org.python.pydev.jython/jysrc/pyedit_import_to_string.py as an example).
For the text selection, the PySelection implementation may be found at: https://github.com/aptana/Pydev/blob/master/plugins/org.python.pydev.core/src/org/python/pydev/core/docutils/PySelection.java (so, you can see how getSelectedText and work your own version to get the text you want).
Here is a little PyDev script that I was able to create with the hints given by Fabio. If you press Ctrl+2,t then the literal string at the cursor position will be surrounded with a gettext call. I'm not sure whether I'm using the Java API as expected, but it works for me. If you have ideas for improvement, please comment.
if cmd == 'onCreateActions':
from org.eclipse.jface.action import Action
from org.python.pydev.core import IPythonPartitions
from org.python.pydev.core.docutils import ParsingUtils, PySelection
class AddGettext(Action):
"""Add gettext call around literal string at cursor position."""
GETTEXT = '_'
def run(self):
sel = PySelection(editor)
doc = sel.getDoc()
pos = sel.getAbsoluteCursorOffset()
ctype = ParsingUtils.getContentType(doc, pos)
if ctype == IPythonPartitions.PY_SINGLELINE_STRING1:
char, multi = "'", False
elif ctype == IPythonPartitions.PY_SINGLELINE_STRING2:
char, multi = '"', False
elif ctype == IPythonPartitions.PY_MULTILINE_STRING1:
char, multi = "'", True
elif ctype == IPythonPartitions.PY_MULTILINE_STRING2:
char, multi = '"', True
else:
char = None
if char:
par = ParsingUtils.create(doc)
if multi:
start = par.findPreviousMulti(pos, char)
end = par.findNextMulti(pos, char)
else:
start = par.findPreviousSingle(pos, char)
end = par.findNextSingle(pos, char)
doc.replace(end + 1, 0, ')')
doc.replace(start, 0, self.GETTEXT + '(')
ACTIVATION_STRING = 't'
WAIT_FOR_ENTER = False
editor.addOfflineActionListener(
ACTIVATION_STRING, AddGettext(), 'Add gettext call', WAIT_FOR_ENTER)
Here is another solution using Vrapper:
:map gt ca'_(<esc>pa)<esc>
Note that this only works with single-quoted strings, it does not recognize when you use double quotes or multi-line strings.