【问题标题】:GtkSourceView/Buffer crash: Gtk-ERROR: Byte index is off the end of the lineGtkSourceView/Buffer 崩溃:Gtk-ERROR: Byte index is off the end of the line
【发布时间】:2019-12-05 07:27:14
【问题描述】:

我一直致力于编写故事的文本编辑器。我正在使用 Python、GTK+ 3 和 GtkSourceView 3。编辑器的要点是折叠某些区域。虽然没有 - 还没有? - 在 GTK TextView / SourceView 中内置折叠支持,我一直使用带有 invisible=True 的标签和 SourceView 的源标记来实现该功能。

此处提供源代码:https://github.com/mkoskim/mawe

核心编辑器(SourceBuffer 和 SourceView)位于:https://github.com/mkoskim/mawe/blob/master/gui/gtk/SceneView.py https://github.com/mkoskim/mawe/blob/master/gui/gtk/SceneBuffer.py

出于测试目的,您可以克隆 repo,然后运行应用程序:

mawe$ ./mawe.py test/test.txt

现在,应用程序不断频繁地随机崩溃,出现如下错误:

(mawe.py:10556): Gtk-WARNING **: /build/gtk+3.0-2Ut_nl/gtk+3.0-3.18.9/./gtk/gtktextbtree.c:4034: byte index off the end of the line
(mawe.py:10556): Gtk-ERROR **: Byte index 1362 is off the end of the line
Trace/breakpoint trap

没有其他错误或警告日志。我一直在谷歌搜索错误,但没有成功。

其他症状似乎是:

  • 即使编辑器处于空闲状态也会发生崩溃

  • 今天我奇怪的是,通过将鼠标移到隐藏部分上,我可以非常快速地崩溃:o

我不能 100% 确定,但我认为这与不可见区域有关。

问题:有没有人碰巧知道这是否是一些已知的错误?

问题:是否有人对我可以寻找可能的解决方案有任何想法?有什么想法会导致崩溃,以及我可以更深入地探索什么?


更新:我用标签做了一些更广泛的测试。似乎没有其他属性对鼠标移动做出反应,但是当打开不可见性时,鼠标在区域上移动会使应用程序崩溃。我一直在搜索报告鼠标事件崩溃 gtktextbtree,但到目前为止没有成功。看起来这适用于多个 v3.x GTK 版本。


更新:我想我几乎找到了解决方法:从 GtkSource.View 过滤掉运动通知事件似乎有效,如下所示:

def filter_event(widget, event, *args):
    # Allow these
    if event.type == Gdk.EventType.KEY_PRESS: return False
    if event.type == Gdk.EventType.KEY_RELEASE: return False

    # Block these
    if event.type == Gdk.EventType.LEAVE_NOTIFY: return True
    if event.type == Gdk.EventType.MOTION_NOTIFY: return True

    # Print & allow the rest
    print(event)
    return False

self.text.connect("event", filter_event)

如果您在隐藏线附近按下鼠标按钮,应用程序仍然会崩溃,但似乎它不会再因鼠标移动而崩溃。


更新:更多调查。虽然阻止鼠标事件可以防止崩溃,但它也会导致怪癖,例如无法使用鼠标放置光标,选择区域,DnD,...此外,鼠标光标可能会消失,因为它不是每次都正确更新。我很确定将鼠标/窗口坐标转换为缓冲区位置的算法存在错误(当文本中有较大的隐藏块时),因此任何鼠标事件都可能使应用程序崩溃。


更新:我一直在尝试为该主题创建简单的测试用例。好事:隐藏似乎奏效了。坏事:还不能重现问题。测试脚本可以在这里找到:

https://github.com/mkoskim/mawe/blob/master/gui/gtk/test/hidecrash/hidecrash.py


更新:试图弄清楚 - 测试用例有效,编辑器不起作用。测试用例的区别至少在于编辑器将隐藏标签放入事件循环(*)中。试图为此做一个测试用例......

(*) 用当前的 Gtk SourceView/TextView 实现折叠肯定有很多不同的解决方案。我选择了使用“标记”语言并在编辑时应用折叠的方法,因为它适用于撤消/重做。我也尝试过其他解决方案,例如:

  1. 剪切折叠场景并将小部件插入到文本缓冲区,其中包含文本本身。想法:“文本[选择用于折叠的部分]文本”->“文本[锚+带有剪切文本的小部件]文本”-遗憾的是,它不适用于撤消/重做。

  2. 剪切文本,给它一个 ID,然后在缓冲区中放置一个包含 ID 的特殊标记部分。想法“文本[选择用于折叠的部分]文本”->“文本[ID w/隐藏+受保护标签]文本”-不起作用,因为剪切'n'粘贴或撤消/重做不应用标签,所以用户可以销毁标记。

  3. 普通标记:尝试使用折叠指示器保留标记非常困难。您需要带有受保护标签的“[char][mark][char]”之类的东西,以确保您不会在某处丢失标记。

无论如何,我会继续调查。


更新:仍然无法在我的测试脚本中重现该问题,但发现了一些可能有趣的东西:折叠最后一个场景不会导致崩溃 - 只有在折叠跟随另一个场景(折叠或未折叠)的场景时。

【问题讨论】:

    标签: python gtk3 gtksourceview


    【解决方案1】:

    我已经解决了这个问题。我只是不明白它为什么起作用,以及为什么我不能用测试脚本重现问题。这是执行折叠的 sn-p:

    fold_start = at.copy()
    fold_start.forward_to_line_end()
    fold_start.forward_char() # Comment this line -> crash
    fold_end = self.scene_end_iter(end)
    self.apply_tag(self.tag_fold_hide, fold_start, fold_end)
    

    at 派生于插入文本或删除范围回调并指向行开始。 fold_end 是到下一个场景标记或文件结尾的 TextIter。如果我们查看缓冲区内容,它是这样的:

    <mark 1><at>Scene 1 heading<eol>
    Line
    Line
    <mark 2>Scene 2 heading
    

    将隐藏标签从 &lt;eol&gt; 应用到 &lt;mark 2&gt; 会导致崩溃。将标签从 &lt;eol + 1&gt; 应用到 &lt;mark 2&gt; 按预期工作。如果折叠到文件末尾 (&lt;mark 2&gt; == buffer.get_end_iter()),则折叠有效。在某些情况下,如果只是隐藏换行符,它也可以工作,但并非在所有情况下都有效。

    如前所述,我不明白为什么会这样,以及为什么我不能用更简单的脚本重现问题,但我一直在调查更多,尽管现在修复时并不那么紧急。

    【讨论】:

      【解决方案2】:

      好的,所以昨天我这样做了,可见部分和不可见部分都使用相似的字体描述进行格式化。我仍然无法用简单的测试脚本重现这个问题,但似乎如果可见部分和隐藏部分离它们太远,偏移计算就会出现问题。到目前为止,我知道:

      • 错误消息,如 Byte index 1362 is off the end of the line Trace/breakpoint trap,与隐藏部分的长度相差约 5-7 个字节。

      • 当可见部分和不可见部分在字体大小、填充和粗细方面彼此“足够接近”时,不会出现错误。在我的工作示例中,我将不可见部分格式化为完全相同的字体、粗细、大小等,并且程序不再崩溃。

      【讨论】:

        猜你喜欢
        • 2022-12-02
        • 1970-01-01
        • 1970-01-01
        • 2015-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-16
        相关资源
        最近更新 更多