Skip to content

Cannot call send_message with python string #32

Open

Description

@scriptum

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.

Activity

  1. elextr commented on Jul 16, 2015

    @elextr
    Collaborator

    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.

  2. scriptum commented on Jul 16, 2015

    @scriptum
    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.

  3. elextr commented on Jul 16, 2015

    @elextr
    Collaborator

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

  4. codebrainz commented on Jul 16, 2015

    @codebrainz
    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.

  5. scriptum commented on Jul 16, 2015

    @scriptum
    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 }
     };
    
  6. codebrainz commented on Jul 16, 2015

    @codebrainz
    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.

  7. scriptum commented on Jul 17, 2015

    @scriptum
    Author

    I tested on this:

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

    Works well.

  8. added a commit that references this issue on Jul 17, 2015
    e72da09
  9. kugel- commented on Mar 6, 2016

    @kugel-
    Collaborator

    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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions