Skip to content

Commit

Permalink
Gracefully avoid linebreak within short candidates
Browse files Browse the repository at this point in the history
  • Loading branch information
LEOYoon-Tsaw committed May 21, 2024
1 parent dde575c commit 67bf288
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 2 deletions.
10 changes: 9 additions & 1 deletion sources/SquirrelPanel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,11 @@ final class SquirrelPanel: NSPanel {

let line = NSMutableAttributedString(string: theme.candidateFormat, attributes: labelAttrs)
for range in line.string.ranges(of: /\[candidate\]/) {
line.addAttributes(attrs, range: convert(range: range, in: line.string))
let convertedRange = convert(range: range, in: line.string)
line.addAttributes(attrs, range: convertedRange)
if candidate.count <= 5 {
line.addAttribute(.noBreak, value: true, range: NSMakeRange(convertedRange.location+1, convertedRange.length-1))
}
}
for range in line.string.ranges(of: /\[comment\]/) {
line.addAttributes(commentAttrs, range: convert(range: range, in: line.string))
Expand All @@ -233,6 +237,10 @@ final class SquirrelPanel: NSPanel {
line.mutableString.replaceOccurrences(of: "[candidate]", with: candidate, range: NSMakeRange(0, line.length))
line.mutableString.replaceOccurrences(of: "[comment]", with: comment, range: NSMakeRange(0, line.length))

if line.length <= 10 {
line.addAttribute(.noBreak, value: true, range: NSMakeRange(1, line.length-1))
}

let lineSeparator = NSAttributedString(string: linear ? " " : "\n", attributes: attrs)
if i > 0 {
text.append(lineSeparator)
Expand Down
19 changes: 18 additions & 1 deletion sources/SquirrelView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import AppKit
final class SquirrelView: NSView {
let textView: NSTextView

private let squirrelLayoutDelegate: SquirrelLayoutDelegate
var candidateRanges: [NSRange] = []
var hilightedIndex = 0
var preeditRange = NSMakeRange(NSNotFound, 0)
Expand All @@ -33,10 +34,12 @@ final class SquirrelView: NSView {
}

override init(frame frameRect: NSRect) {
squirrelLayoutDelegate = SquirrelLayoutDelegate()
textView = NSTextView(frame: frameRect)
textView.drawsBackground = false
textView.isEditable = false
textView.isSelectable = false
textView.textLayoutManager?.delegate = squirrelLayoutDelegate
super.init(frame: frameRect)
textContainer.lineFragmentPadding = 0
self.wantsLayer = true
Expand All @@ -57,7 +60,7 @@ final class SquirrelView: NSView {
guard range.location != NSNotFound else { return nil }
guard let startLocation = textLayoutManager.location(textLayoutManager.documentRange.location, offsetBy: range.location) else { return nil }
guard let endLocation = textLayoutManager.location(startLocation, offsetBy: range.length) else { return nil }
return NSTextRange(location: startLocation, end: endLocation) ?? textLayoutManager.documentRange
return NSTextRange(location: startLocation, end: endLocation)
}

// Get the rectangle containing entire contents, expensive to calculate
Expand Down Expand Up @@ -679,3 +682,17 @@ private extension SquirrelView {
return newRect
}
}

fileprivate class SquirrelLayoutDelegate: NSObject, NSTextLayoutManagerDelegate {
func textLayoutManager(_ textLayoutManager: NSTextLayoutManager, shouldBreakLineBefore location: any NSTextLocation, hyphenating: Bool) -> Bool {
let index = textLayoutManager.offset(from: textLayoutManager.documentRange.location, to: location)
if let attributes = textLayoutManager.textContainer?.textView?.textContentStorage?.attributedString?.attributes(at: index, effectiveRange: nil), let noBreak = attributes[.noBreak] as? Bool, noBreak {
return false
}
return true
}
}

extension NSAttributedString.Key {
static let noBreak = NSAttributedString.Key("noBreak")
}

0 comments on commit 67bf288

Please sign in to comment.