-
Notifications
You must be signed in to change notification settings - Fork 3
/
NSTextView+ClickableLinks.m
110 lines (95 loc) · 3.45 KB
/
NSTextView+ClickableLinks.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//
// NSTextView+ClickableLinks.m
// Jabber
//
// Created by David Chisnall on 24/05/2007.
// Copyright 2007 __MyCompanyName__. All rights reserved.
//
#import "NSTextView+ClickableLinks.h"
#ifdef GNUSTEP
#define NSCursorAttributeName @"NSCursorAttributeName"
#endif
@implementation NSTextView (ClickableLinks)
- (void)makeLinksClickable
{
NSTextStorage* textStorage = [self textStorage];
NSString* string = [textStorage string];
unsigned int length = [string length];
NSRange searchRange = NSMakeRange(0, length);
NSRange foundRange;
NSCharacterSet * whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
[textStorage beginEditing];
do
{
/* Find the protocol://path separator. */
foundRange=[string rangeOfString:@"://" options:0 range:searchRange];
/* If there was a URL */
if (foundRange.length > 0)
{
NSRange startOfURLRange, endOfURLRange;
/* Search backwards to find the start of the URL */
searchRange.location = 0;
searchRange.length = foundRange.location;
startOfURLRange = [string rangeOfCharacterFromSet:whitespace
options:NSBackwardsSearch
range:searchRange];
if(startOfURLRange.length == 0)
{
startOfURLRange.location = 0;
}
else
{
startOfURLRange.location++;
}
/* Assume the URL ends with whitespace */
searchRange.location = foundRange.location + 3;
searchRange.length = length - searchRange.location;
endOfURLRange = [string rangeOfCharacterFromSet:whitespace
options:0
range:searchRange];
if (endOfURLRange.length == 0)
{
endOfURLRange.location = length;
}
/* Set foundRange to the URL range */
foundRange.location = startOfURLRange.location;
foundRange.length = endOfURLRange.location-foundRange.location;
/* Range starting after the link */
NSRange afterLink;
afterLink.location = foundRange.location + foundRange.length;
afterLink.length = 0;
/* Don't do anything for tiny things that look like links. */
if(foundRange.length > 4)
{
NSString * urlString = [string substringWithRange:foundRange];
/* Trim brackets */
if([urlString characterAtIndex:0] == '('
&&
[urlString characterAtIndex:[urlString length]-1] == ')')
{
urlString = [urlString substringWithRange:NSMakeRange(1,[urlString length] -2)];
}
/* Make a URL from the link text */
NSURL * url = [NSURL URLWithString:urlString];
NSDictionary * linkAttributes= [NSDictionary dictionaryWithObjectsAndKeys:
url, NSLinkAttributeName,
[NSNumber numberWithInt:NSSingleUnderlineStyle], NSUnderlineStyleAttributeName,
[NSCursor pointingHandCursor],NSCursorAttributeName,
[NSColor blueColor], NSForegroundColorAttributeName,
nil];
/* Clickify the link */
[textStorage addAttributes:linkAttributes range:foundRange];
/* Reset attributes for after the link */
[textStorage removeAttribute:NSLinkAttributeName range:afterLink];
[textStorage removeAttribute:NSCursorAttributeName range:afterLink];
[textStorage removeAttribute:NSUnderlineStyleAttributeName range:afterLink];
[textStorage removeAttribute:NSForegroundColorAttributeName range:afterLink];
}
/* Search after the end of the link */
searchRange.location = afterLink.location;
searchRange.length = length - searchRange.location;
}
} while (foundRange.length!=0); //repeat the do block until it no longer finds anything
[textStorage endEditing];
}
@end