如何通过双击使NSTextView余额定界符? [英] How to make NSTextView balance delimiters with a double-click?

查看:124
本文介绍了如何通过双击使NSTextView余额定界符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常有一个文本编辑器来处理代码或其他结构化内容,以平衡某种定界符.当您双击{时,它会选择匹配的},或者类似地用于()对,[]对等.如何在Cocoa/Obj-C的NSTextView中实现此行为?

It's common to have a text editor for code or other structured content that balances delimiters of some sort; when you double click on a { it selects to the matching }, or similarly for ( ) pairs, [ ] pairs, etc. How can I implement this behavior in NSTextView in Cocoa/Obj-C?

(我将暂时发布一个答案,因为我对此一无所获,并花费了今天实施解决方案.欢迎提供更好的答案.)

(I will be posting an answer momentarily, since I found nothing on SO about this and spent today implementing a solution. Better answers are welcome.)

附录:

这与此问题不同.有关NSTextField的信息,主要涉及NSTextField和字段编辑器的问题. 如果通过将自定义NSTextView子类替换为字段编辑器来解决该问题,那么该自定义子类当然可以使用此处提供的解决方案;但是可能还有许多其他方法可以解决NSTextField的问题,并且将自定义NSTextView子类替换为字段编辑器显然不是解决该问题的正确方法,无论如何,程序员在NSTextView(这可能是更常见的问题)可能不太关心所有这些NSTextField和字段编辑器问题.因此,这是一个不同的问题–尽管我将添加该问题的链接到该问题,以作为可能的方向.

This is not the same as this question, which is about NSTextField and is primarily concerned with NSTextField and field editor issues. If that question is solved by substituting a custom NSTextView subclass into the field editor, then that custom subclass could use the solution given here, of course; but there might be many other ways to solve the problem for NSTextField, and substituting a custom NSTextView subclass into the field editor is not obviously the right solution to that problem, and in any case a programmer concerned with delimiter balancing in NSTextView (which is presumably the more common problem) could care less about all of those NSTextField and field editor issues. So that is a different question – although I will add a link from that question to this one, as one possible direction it could go.

这也与此问题不同,双击时在NSTextView中单词"的定义.根据 Apple的文档 ,这些是采用不同解决方案的不同问题;对于定界符平衡(此问题),Apple特别建议使用NSTextViewselectionRangeForProposedRange:granularity:方法,而对于更改单词的定义(该问题),Apple特别声明selectionRangeForProposedRange:granularity:方法不应 .

This is also not the same as this question, which is really about changing the definition of a "word" in NSTextView when a double-click occurs. As per Apple's documentation, these are different problems with different solutions; for delimiter-balancing (this question) Apple specifically recommends the use of NSTextView's selectionRangeForProposedRange:granularity: method, whereas for changing the definition of a word (that question) Apple specifically states that the selectionRangeForProposedRange:granularity: method should not be used.

推荐答案

在其可可文本体系结构指南(

In their Cocoa Text Architecture Guide (https://developer.apple.com/library/prerelease/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/TextEditing/TextEditing.html), Apple suggests subclassing NSTextView and overriding selectionRangeForProposedRange:granularity: to achieve this sort of thing; they even say "For example, in a code editor you can provide a delegate that extends a double click on a brace or parenthesis character to its matching delimiter." However, it is not immediately clear how to achieve this, since you want the delimiter match to happen only at after a simple double-click on a delimiter, not after a double-click-drag or even a double-click-hold-release.

我能想到的最好的解决方案包括覆盖mouseDown:,并做一些关于事务状态的记账工作.也许有一种更简单的方法.我省略了实际上计算分隔符匹配的代码的核心部分.这取决于您要匹配的分隔符,可能存在的语法复杂性(字符串,注释)等等.在我的代码中,我实际上调用了一个令牌生成器来获取令牌流,然后使用它来查找匹配的定界符. YMMV.所以,这就是我所拥有的:

The best solution I could come up with involves overriding mouseDown: as well, and doing a little bookkeeping about the state of affairs. Maybe there is a simpler way. I've left out the core part of the code where the delimiter match actually gets calculated; that will depend on what delimiters you're matching, what syntactical complexities (strings, comments) might exist, and so forth. In my code I actually call a tokenizer to get a token stream, and I use that to find the matching delimiter. YMMV. So, here's what I've got:

在您的NSTextView子类界面(或更好的类扩展)中:

In your NSTextView subclass interface (or class extension, better yet):

// these are used in selectionRangeForProposedRange:granularity:
// to balance delimiters properly
BOOL inEligibleDoubleClick;
NSTimeInterval doubleDownTime;

在您的NSTextView子类实现中:

- (void)mouseDown:(NSEvent *)theEvent
{
    // Start out willing to work with a double-click for delimiter-balancing;
    // see selectionRangeForProposedRange:proposedCharRange granularity: below
    inEligibleDoubleClick = YES;

    [super mouseDown:theEvent];
}

- (NSRange)selectionRangeForProposedRange:(NSRange)proposedCharRange
    granularity:(NSSelectionGranularity)granularity
{
    if ((granularity == NSSelectByWord) && inEligibleDoubleClick)
    {
        // The proposed range has to be zero-length to qualify
        if (proposedCharRange.length == 0)
        {
            NSEvent *event = [NSApp currentEvent];
            NSEventType eventType = [event type];
            NSTimeInterval eventTime = [event timestamp];

            if (eventType == NSLeftMouseDown)
            {
                // This is the mouseDown of the double-click; we do not want
                // to modify the selection here, just log the time
                doubleDownTime = eventTime;
            }
            else if (eventType == NSLeftMouseUp)
            {
                // After the double-click interval since the second mouseDown,
                // the mouseUp is no longer eligible
                if (eventTime - doubleDownTime <= [NSEvent doubleClickInterval])
                {
                    NSString *scriptString = [[self textStorage] string];

                    ...insert delimiter-finding code here...
                    ...return the matched range, or NSBeep()...
                }
                else
                {
                    inEligibleDoubleClick = false;
                }
            }
            else
            {
                inEligibleDoubleClick = false;
            }
        }
        else
        {
            inEligibleDoubleClick = false;
        }
    }

    return [super selectionRangeForProposedRange:proposedCharRange
        granularity:granularity];
}

这有点脆弱,因为它依赖于NSTextView的跟踪以特定的方式工作并以特定的方式调用selectionRangeForProposedRange:granularity:,但是假设并不大.我认为它非常健壮.

It's a little fragile, because it relies on NSTextView's tracking working in a particular way and calling out to selectionRangeForProposedRange:granularity: in a particular way, but the assumptions are not large; I imagine it's pretty robust.

这篇关于如何通过双击使NSTextView余额定界符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆