Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot call send_message with python string #32

Open
scriptum opened this issue Jul 16, 2015 · 8 comments
Open

Cannot call send_message with python string #32

scriptum opened this issue Jul 16, 2015 · 8 comments

Comments

@scriptum
Copy link

I'm trying to write simple autocomplete plugin:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import geany, os, gettext, re, glob
from ctypes import *
gsc = geany.scintilla
gsc.WORDSTARTPOSITION = 2266
gsc.AUTOCSHOW = 2100
gsc.AUTOCACTIVE = 2102
class AutocompleteFilePlugin(geany.Plugin):

    __plugin_name__ = "Autocomplete file names"
    __plugin_description__ = ("Autocompletion based on existing files")
    __plugin_version__ = "0.1"
    __plugin_author__ = "Pavel Roschin <rpg89(at)post(dot)ru>"

    def editor_cb(self, obj, editor, nt):
        if nt.nmhdr.code != gsc.MODIFIED: return False
        if not nt.modification_type & (gsc.MOD_INSERT_TEXT | gsc.MOD_DELETE_TEXT): return False
        sci = editor.scintilla
        if sci.has_selection(): return False
        ssm = sci.send_message
        if ssm(gsc.AUTOCACTIVE): return False
        line = sci.get_current_line()
        start = sci.get_position_from_line(line)
        end = sci.get_current_position()
        if nt.modification_type & gsc.MOD_INSERT_TEXT: end += 1
        if start == end: return False
        col = sci.get_col_from_position(end)
        if col > 100: return False
        text = sci.get_contents_range(start, end)
        match = re.search('[^\s\'"<>()]+$', text)
        if not match: return False
        path = match.group(0)
        paths = glob.glob(path+'*')
        if len(paths) == 0: return False
        print "\n".join(paths)
        # ssm(gsc.AUTOCSHOW, len(path), "\n".join(paths))

    def __init__(self):
        geany.Plugin.__init__(self)
        geany.signals.connect("editor-notify", self.editor_cb)

Problematic line: ssm(gsc.AUTOCSHOW, len(path), "\n".join(paths)). Geany crashes if string passed to send_message function.

@elextr
Copy link
Collaborator

elextr commented Jul 16, 2015

The third argument to send_message is expected to be a long (see here) not a char* and certainly not a Python string. This seems reasonable since Python doesn't use pointers anyway, so the sptr argument to Scintilla send_message is defined for those few places where a non-pointer argument is used.

You might get the Python string converted to char* and then to long using the appropriate ctypes functions and then pass that.

But note you can't pass a pointer in a long on windows 64, so its not portable anyway.

@scriptum
Copy link
Author

Is it possible to add into geanypy another interface (maybe with same name?) which accepts python strings and does all casting inside C module?

I'm looking for any possible solution to call SCI_AUTOCSHOW from python.

@elextr
Copy link
Collaborator

elextr commented Jul 16, 2015

It probably could be done send_text_message( message, otherarg, string) or similar.

@codebrainz
Copy link
Owner

Scintilla_send_message should probably use Scintilla's typedefs uptr_t and sptr_t or GLib's guintptr and gintptr (or std C's uintptr_t/intptr_t) rather than glong/long, in order to portably fit a pointer in it.

@scriptum
Copy link
Author

Patch:

diff --git a/geanypy/src/geanypy-scintilla.c b/geanypy/src/geanypy-scintilla.c
index 9b3776d..8de6a22 100644
--- a/geanypy/src/geanypy-scintilla.c
+++ b/geanypy/src/geanypy-scintilla.c
@@ -783,6 +783,26 @@ Scintilla_send_message(Scintilla *self, PyObject *args, PyObject *kwargs)
 }


+static PyObject *
+Scintilla_send_text_message(Scintilla *self, PyObject *args, PyObject *kwargs)
+{
+   gint msg;
+   glong uptr = 0, ret;
+   const char *sptr = NULL;
+   static gchar *kwlist[] = { "msg", "lparam", "wparam", NULL };
+
+   SCI_RET_IF_FAIL(self);
+
+   if (PyArg_ParseTupleAndKeywords(args, kwargs, "i|lz", kwlist, &msg, &uptr, &sptr))
+   {
+       ret = scintilla_send_message(self->sci, msg, uptr, sptr);
+       return Py_BuildValue("l", ret);
+   }
+
+   Py_RETURN_NONE;
+}
+
+
 static PyMethodDef Scintilla_methods[] = {
    { "delete_marker_at_line", (PyCFunction) Scintilla_delete_marker_at_line, METH_KEYWORDS,
        "Deletes a line marker." },
@@ -877,6 +897,8 @@ static PyMethodDef Scintilla_methods[] = {
        "Begins grouping a set of edits together as one Undo action." },
    { "send_message", (PyCFunction) Scintilla_send_message, METH_KEYWORDS,
        "Send a message to the Scintilla widget." },
+   { "send_text_message", (PyCFunction) Scintilla_send_text_message, METH_KEYWORDS,
+       "Send a text message to the Scintilla widget." },
    { NULL }
 };

@codebrainz
Copy link
Owner

For the z format, I'm not sure if Scintilla handles NULL arguments. I've had sometimes feeding bad args to Scintilla and it just crashes. I guess if you tested some string functions and it works, it's ok, otherwise we could do like sptr?sptr:"" or whatever.

@scriptum
Copy link
Author

I tested on this:

sci.send_text_message(gsc.AUTOCSHOW, 0, None)

Works well.

scriptum added a commit to scriptum/geanypy that referenced this issue Jul 17, 2015
Geany crashes if Python string passed to SSM. Use this function if last argument of SSM is string. Fixes codebrainz#32
This was referenced Jul 17, 2015
@kugel-
Copy link
Collaborator

kugel- commented Mar 6, 2016

I faced the scintilla_send_message() problem with peasy as well. I decided to not do anything about it for now (you'd need to provide a wrapper for every arg combination) but instead just rely on all necessary functionality being wrapped by Geany' sci_* functions which can be called (and may add value).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants