-
Notifications
You must be signed in to change notification settings - Fork 107
Improvements and fixes to NSTextList-related code #297
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
base: master
Are you sure you want to change the base?
Changes from all commits
b0faa3a
9d63a86
3c47847
44a42dd
7f42e27
2bfb0bd
65ee825
b00f6e5
083c6c4
462d4f5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,6 +53,7 @@ | |
#import "AppKit/NSFont.h" | ||
#import "AppKit/NSFontDescriptor.h" | ||
#import "AppKit/NSFontManager.h" | ||
#import "AppKit/NSTextList.h" | ||
// For the colour name spaces | ||
#import "AppKit/NSGraphics.h" | ||
#import "AppKit/NSTextTable.h" | ||
|
@@ -1095,20 +1096,43 @@ - (NSFileWrapper *) fileWrapperFromRange: (NSRange)range | |
- (NSInteger) itemNumberInTextList: (NSTextList *)list | ||
atIndex: (NSUInteger)location | ||
{ | ||
NSParagraphStyle *style = [self attribute: NSParagraphStyleAttributeName | ||
atIndex: location | ||
effectiveRange: NULL]; | ||
if (style != nil) | ||
NSRange listRange = [self rangeOfTextList: list atIndex: location]; | ||
if (listRange.location == NSNotFound) | ||
{ | ||
NSArray *textLists = [style textLists]; | ||
return 0; | ||
} | ||
|
||
if (textLists != nil) | ||
NSRange subRange = NSMakeRange(listRange.location, location-listRange.location+1); | ||
unichar buffer[subRange.length]; | ||
|
||
[[self string] getCharacters: buffer range: subRange]; | ||
|
||
NSCharacterSet *newlineCharacterSet = [NSCharacterSet newlineCharacterSet]; | ||
|
||
NSUInteger itemNumber = 1; | ||
NSUInteger index; | ||
for (index=1; index<subRange.length; index++) | ||
{ | ||
if ([newlineCharacterSet characterIsMember: buffer[index-1]]) | ||
{ | ||
return [textLists indexOfObject: list]; | ||
NSParagraphStyle *style = [self attribute: NSParagraphStyleAttributeName | ||
atIndex: subRange.location + index | ||
effectiveRange: NULL]; | ||
|
||
NSArray *textLists = [style textLists]; | ||
if ([list isEqual: [textLists lastObject]]) | ||
{ | ||
itemNumber++; | ||
} | ||
|
||
if (buffer[index-1] == '\r' && buffer[index] == '\n') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This and the use of |
||
{ | ||
index++; | ||
} | ||
} | ||
} | ||
|
||
return NSNotFound; | ||
return itemNumber; | ||
} | ||
|
||
- (NSRange) rangeOfTextBlock: (NSTextBlock *)block | ||
|
@@ -1183,7 +1207,7 @@ - (NSRange) rangeOfTextList: (NSTextList *)list | |
NSRange newEffRange; | ||
NSUInteger len = [self length]; | ||
|
||
while ((effRange.location > 0) && style && textLists) | ||
while (effRange.location > 0) | ||
{ | ||
style = [self attribute: NSParagraphStyleAttributeName | ||
atIndex: effRange.location - 1 | ||
|
@@ -1196,11 +1220,13 @@ - (NSRange) rangeOfTextList: (NSTextList *)list | |
{ | ||
effRange.location = newEffRange.location; | ||
effRange.length += newEffRange.length; | ||
continue; | ||
} | ||
} | ||
break; | ||
} | ||
|
||
while (NSMaxRange(effRange) < len && style && textLists) | ||
while (NSMaxRange(effRange) < len) | ||
{ | ||
style = [self attribute: NSParagraphStyleAttributeName | ||
atIndex: NSMaxRange(effRange) | ||
|
@@ -1212,8 +1238,10 @@ - (NSRange) rangeOfTextList: (NSTextList *)list | |
if ((textLists != nil) && [textLists containsObject: list]) | ||
{ | ||
effRange.length += newEffRange.length; | ||
continue; | ||
} | ||
} | ||
break; | ||
} | ||
|
||
return effRange; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -303,6 +303,8 @@ - (id) init | |
[_tabStops addObject: tab]; | ||
RELEASE(tab); | ||
} | ||
|
||
ASSIGN(_textLists, [NSArray array]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instances in Cocoa always have an empty array set for the default value, so I included this here and below. We weren't even saving the textLists in some of the serialization paths, and other fields like text blocks and text tables are ignored as well. I'd suggest deferring any work on that part unless we make the changes as a batch and bump the object version; I'm not that familiar with any of this yet, and I don't want the PR to get out of hand. |
||
} | ||
return self; | ||
} | ||
|
@@ -494,6 +496,9 @@ - (id) initWithCoder: (NSCoder*)aCoder | |
[aCoder decodeValueOfObjCType: @encode(float) at: &_paragraphSpacing]; | ||
[aCoder decodeValueOfObjCType: @encode(float) at: &_tailIndent]; | ||
|
||
// Text lists were not included for non-keyed encoding, use a default | ||
ASSIGN(_textLists, [NSArray array]); | ||
|
||
/* | ||
* Tab stops don't conform to NSCoding - so we do it the long way. | ||
*/ | ||
|
@@ -621,7 +626,12 @@ - (BOOL) isEqual: (id)aother | |
C(_headerLevel); | ||
#undef C | ||
|
||
return [_tabStops isEqualToArray: other->_tabStops]; | ||
#define C(x) if (![x isEqualToArray: other->x]) return NO; | ||
C(_tabStops); | ||
C(_textLists); | ||
#undef C | ||
|
||
return YES; | ||
} | ||
|
||
- (NSUInteger) hash | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
#include "Testing.h" | ||
|
||
#include <Foundation/NSAutoreleasePool.h> | ||
#include <AppKit/NSAttributedString.h> | ||
#include <AppKit/NSParagraphStyle.h> | ||
#include <AppKit/NSTextList.h> | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
CREATE_AUTORELEASE_POOL(arp); | ||
|
||
START_SET("NSAttributedString itemNumberInTextList:atIndex: category method"); | ||
|
||
NSTextList *list1 = [[NSTextList alloc] initWithMarkerFormat:@"{decimal}" options:0]; | ||
NSTextList *list2 = [[NSTextList alloc] initWithMarkerFormat:@"{box}" options:0]; | ||
|
||
NSMutableParagraphStyle *style1 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; | ||
NSMutableParagraphStyle *style2 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; | ||
|
||
[style1 setTextLists: [NSArray arrayWithObject: list1]]; | ||
[style2 setTextLists: [NSArray arrayWithObjects: list1, list2, nil]]; | ||
|
||
NSDictionary *attrs1 = [NSDictionary dictionaryWithObject: style1 | ||
forKey: NSParagraphStyleAttributeName]; | ||
NSDictionary *attrs2 = [NSDictionary dictionaryWithObject: style2 | ||
forKey: NSParagraphStyleAttributeName]; | ||
NSDictionary *attrs3 = [NSDictionary dictionaryWithObject: [NSParagraphStyle defaultParagraphStyle] | ||
forKey: NSParagraphStyleAttributeName]; | ||
|
||
NSMutableAttributedString *storage = [[NSMutableAttributedString alloc] init]; | ||
|
||
NSUInteger index1 = [storage length]; | ||
[storage appendAttributedString: | ||
[[NSMutableAttributedString alloc] initWithString: @"item 1\r\n" attributes: attrs1]]; | ||
|
||
NSUInteger index2 = [storage length]; | ||
[storage appendAttributedString: | ||
[[NSMutableAttributedString alloc] initWithString: @"item 2\n" attributes: attrs1]]; | ||
|
||
NSUInteger index3 = [storage length]; | ||
[storage appendAttributedString: | ||
[[NSMutableAttributedString alloc] initWithString: @"item 3\n" attributes: attrs1]]; | ||
|
||
NSUInteger index4 = [storage length]; | ||
[storage appendAttributedString: | ||
[[NSMutableAttributedString alloc] initWithString: @"subitem 1\n" attributes: attrs2]]; | ||
|
||
NSUInteger index5 = [storage length]; | ||
[storage appendAttributedString: | ||
[[NSMutableAttributedString alloc] initWithString: @"subitem 2\n" attributes: attrs2]]; | ||
|
||
NSUInteger index6 = [storage length]; | ||
[storage appendAttributedString: | ||
[[NSMutableAttributedString alloc] initWithString: @"item 4\n" attributes: attrs1]]; | ||
|
||
NSUInteger index7 = [storage length]; | ||
[storage appendAttributedString: | ||
[[NSMutableAttributedString alloc] initWithString: @"extra text\n" attributes: attrs3]]; | ||
|
||
pass([storage itemNumberInTextList: list1 atIndex: index1] == 1, "Index for first list item"); | ||
pass([storage itemNumberInTextList: list1 atIndex: index2] == 2, "Index with CR+LF sequence"); | ||
pass([storage itemNumberInTextList: list1 atIndex: index3 - 1] == 2, "Index on boundary"); | ||
pass([storage itemNumberInTextList: list1 atIndex: index3] == 3, "Index for third list item"); | ||
pass([storage itemNumberInTextList: list1 atIndex: index4] == 3, "Index for third list item (sublist 1)"); | ||
pass([storage itemNumberInTextList: list1 atIndex: index5] == 3, "Index for third list item (sublist 2"); | ||
pass([storage itemNumberInTextList: list1 atIndex: index6] == 4, "Index for fourth list item"); | ||
|
||
pass([storage itemNumberInTextList: list2 atIndex: index4] == 1, "Index for first sublist item"); | ||
pass([storage itemNumberInTextList: list2 atIndex: index5] == 2, "Index for second sublist item"); | ||
|
||
pass([storage itemNumberInTextList: list2 atIndex: index1] == 0, "Index in other list is zero"); | ||
pass([storage itemNumberInTextList: list1 atIndex: index7] == 0, "Index in nonlist is zero"); | ||
|
||
END_SET("NSAttributedString itemNumberInTextList:atIndex: category method"); | ||
|
||
DESTROY(arp); | ||
|
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
#include "Testing.h" | ||
|
||
#include <Foundation/NSAutoreleasePool.h> | ||
#include <AppKit/NSAttributedString.h> | ||
#include <AppKit/NSParagraphStyle.h> | ||
#include <AppKit/NSTextList.h> | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
CREATE_AUTORELEASE_POOL(arp); | ||
|
||
START_SET("NSAttributedString attribute merging"); | ||
|
||
NSMutableParagraphStyle *style1 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; | ||
NSMutableParagraphStyle *style2 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; | ||
NSMutableParagraphStyle *style3 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; | ||
NSMutableParagraphStyle *style4 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; | ||
|
||
NSTextList *list1 = [[NSTextList alloc] initWithMarkerFormat: @"{box}" options: 0]; | ||
NSTextList *list2 = [[NSTextList alloc] initWithMarkerFormat: @"{box}" options: 0]; | ||
|
||
[style3 setTextLists: [NSArray arrayWithObject: list1]]; | ||
[style4 setTextLists: [NSArray arrayWithObject: list2]]; | ||
|
||
NSAttributedString *str1 = [[NSAttributedString alloc] | ||
initWithString: @"string 1" | ||
attributes: [NSDictionary dictionaryWithObject: style1 forKey: NSParagraphStyleAttributeName]]; | ||
NSAttributedString *str2 = [[NSAttributedString alloc] | ||
initWithString: @"string 2" | ||
attributes: [NSDictionary dictionaryWithObject: style2 forKey: NSParagraphStyleAttributeName]]; | ||
NSAttributedString *str3 = [[NSAttributedString alloc] | ||
initWithString: @"string 3" | ||
attributes: [NSDictionary dictionaryWithObject: style3 forKey: NSParagraphStyleAttributeName]]; | ||
NSAttributedString *str4 = [[NSAttributedString alloc] | ||
initWithString: @"string 4" | ||
attributes: [NSDictionary dictionaryWithObject: style4 forKey: NSParagraphStyleAttributeName]]; | ||
|
||
NSMutableAttributedString *storage = [[NSMutableAttributedString alloc] init]; | ||
|
||
NSUInteger pos1 = [storage length]; | ||
[storage appendAttributedString: str1]; | ||
|
||
NSUInteger pos2 = [storage length]; | ||
[storage appendAttributedString: str2]; | ||
|
||
NSUInteger pos3 = [storage length]; | ||
[storage appendAttributedString: str3]; | ||
|
||
NSUInteger pos4 = [storage length]; | ||
[storage appendAttributedString: str4]; | ||
|
||
NSParagraphStyle *result1 = [storage attribute: NSParagraphStyleAttributeName | ||
atIndex: pos1 | ||
effectiveRange: NULL]; | ||
NSParagraphStyle *result2 = [storage attribute: NSParagraphStyleAttributeName | ||
atIndex: pos2 | ||
effectiveRange: NULL]; | ||
NSParagraphStyle *result3 = [storage attribute: NSParagraphStyleAttributeName | ||
atIndex: pos3 | ||
effectiveRange: NULL]; | ||
NSParagraphStyle *result4 = [storage attribute: NSParagraphStyleAttributeName | ||
atIndex: pos4 | ||
effectiveRange: NULL]; | ||
|
||
pass(result1 == result2, "Did merge equal paragraph styles"); | ||
pass(result3 != result4, "Did not merge equal paragraph styles with text lists"); | ||
|
||
END_SET("NSAttributedString attribute merging"); | ||
|
||
DESTROY(arp); | ||
|
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#include "Testing.h" | ||
|
||
#include <Foundation/NSAutoreleasePool.h> | ||
#include <AppKit/NSAttributedString.h> | ||
#include <AppKit/NSParagraphStyle.h> | ||
#include <AppKit/NSTextList.h> | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
CREATE_AUTORELEASE_POOL(arp); | ||
|
||
START_SET("NSAttributedString rangeOfTextList:atIndex: category method"); | ||
|
||
NSTextList *list1 = [[NSTextList alloc] initWithMarkerFormat: @"{box}" options: 0]; | ||
NSTextList *list2 = [[NSTextList alloc] initWithMarkerFormat: @"{box}" options: 0]; | ||
NSTextList *list3 = [[NSTextList alloc] initWithMarkerFormat: @"{box}" options: 0]; | ||
|
||
NSMutableParagraphStyle *style1 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; | ||
NSMutableParagraphStyle *style2 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; | ||
NSMutableParagraphStyle *style3 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; | ||
NSMutableParagraphStyle *style4 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; | ||
|
||
[style2 setTextLists: [NSArray arrayWithObject: list1]]; | ||
[style3 setTextLists: [NSArray arrayWithObjects: list1, list2, nil]]; | ||
[style4 setTextLists: [NSArray arrayWithObject: list3]]; | ||
|
||
NSMutableAttributedString *storage = [[NSMutableAttributedString alloc] init]; | ||
|
||
NSUInteger pos1 = [storage length]; | ||
[storage appendAttributedString: [[NSAttributedString alloc] | ||
initWithString: @"before\n" | ||
attributes: [NSDictionary dictionaryWithObject: style1 forKey: NSParagraphStyleAttributeName]]]; | ||
|
||
NSUInteger pos2 = [storage length]; | ||
[storage appendAttributedString: [[NSAttributedString alloc] | ||
initWithString: @"list 1\n" | ||
attributes: [NSDictionary dictionaryWithObject: style2 forKey: NSParagraphStyleAttributeName]]]; | ||
|
||
NSUInteger pos3 = [storage length]; | ||
[storage appendAttributedString: [[NSAttributedString alloc] | ||
initWithString: @"sublist 1\n" | ||
attributes: [NSDictionary dictionaryWithObject: style3 forKey: NSParagraphStyleAttributeName]]]; | ||
|
||
NSUInteger pos4 = [storage length]; | ||
[storage appendAttributedString: [[NSAttributedString alloc] | ||
initWithString: @"list 1\n" | ||
attributes: [NSDictionary dictionaryWithObject: style2 forKey: NSParagraphStyleAttributeName]]]; | ||
|
||
NSUInteger pos5 = [storage length]; | ||
[storage appendAttributedString: [[NSAttributedString alloc] | ||
initWithString: @"list 2\n" | ||
attributes: [NSDictionary dictionaryWithObject: style4 forKey: NSParagraphStyleAttributeName]]]; | ||
|
||
NSUInteger pos6 = [storage length]; | ||
[storage appendAttributedString: [[NSAttributedString alloc] | ||
initWithString: @"ending\n" | ||
attributes: [NSDictionary dictionaryWithObject: style1 forKey: NSParagraphStyleAttributeName]]]; | ||
|
||
NSRange expected, actual; | ||
|
||
expected = NSMakeRange(pos3, pos4 - pos3); | ||
actual = [storage rangeOfTextList: list2 atIndex: pos3 + 1]; | ||
pass(NSEqualRanges(expected, actual), "Found correct range of nested list"); | ||
|
||
expected = NSMakeRange(pos2, pos5 - pos2); | ||
actual = [storage rangeOfTextList: list1 atIndex: pos3 + 1]; | ||
pass(NSEqualRanges(expected, actual), "Found correct range of enclosing list"); | ||
|
||
expected = NSMakeRange(pos2, pos5 - pos2); | ||
actual = [storage rangeOfTextList: list1 atIndex: pos2 + 1]; | ||
pass(NSEqualRanges(expected, actual), "Found correct range including nested list"); | ||
|
||
expected = NSMakeRange(pos5, pos6 - pos5); | ||
actual = [storage rangeOfTextList: list3 atIndex: pos5 + 1]; | ||
pass(NSEqualRanges(expected, actual), "Found correct range of an adjacent list"); | ||
|
||
actual = [storage rangeOfTextList: list1 atIndex: pos5]; | ||
pass(actual.location == NSNotFound, "Returned not found for location in different list"); | ||
|
||
actual = [storage rangeOfTextList: list1 atIndex: pos1]; | ||
pass(actual.location == NSNotFound, "Returned not found for location not in any list"); | ||
|
||
END_SET("NSAttributedString rangeOfTextList:atIndex: category method"); | ||
|
||
DESTROY(arp); | ||
|
||
return 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This matches the return value in Cocoa (I'd have expected
NSNotFound
but it seems to return 0 instead).