Skip to content

Commit

Permalink
Added preference to scroll past end of editor
Browse files Browse the repository at this point in the history
- New preference for editor
- Refactored preference boolean actions slightly
  • Loading branch information
lukakerr committed Mar 21, 2019
1 parent cd6dd48 commit aadd8ac
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 54 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Added RTL writing direction support in editor and preview
- Added preference to show invisible characters
- Added preference to show a toolbar on the window
- Added preference to scroll past end of editor
- Added preferences to sync scroll position between editor and preview
- Added 9 new themes:
- a11y-dark
Expand Down
7 changes: 3 additions & 4 deletions Pine/Controllers/MarkdownViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class MarkdownViewController: NSViewController, NSTextViewDelegate, HighlightDel
NotificationCenter.receive(.appearanceChanged, instance: self, selector: #selector(generatePreview))

// Setup notification observer for when scroll view scrolls
NotificationCenter.receive(.scrollViewScrolled, instance: self, selector: #selector(scrollViewDidScroll))
NotificationCenter.receive(.boundsDidChange, instance: self, selector: #selector(scrollViewDidScroll))

// Setup a 200ms debouncer for generating the markdown preview
debouncedGeneratePreview = Debouncer(delay: 0.2) {
Expand Down Expand Up @@ -120,7 +120,6 @@ class MarkdownViewController: NSViewController, NSTextViewDelegate, HighlightDel
markdownTextView.insertionPointColor = .gray
markdownTextView.isVerticallyResizable = true
markdownTextView.isHorizontallyResizable = false
markdownTextView.textContainerInset = NSSize(width: 10.0, height: 10.0)

if #available(OSX 10.12.2, *) {
markdownTextView.touchBar = self.makeTouchBar()
Expand All @@ -133,11 +132,11 @@ class MarkdownViewController: NSViewController, NSTextViewDelegate, HighlightDel
view.updateLayer()
generatePreview()
layoutManager.fontDidUpdate()
markdownTextView.isContinuousSpellCheckingEnabled = preferences[Preference.spellcheckEnabled]
markdownTextView.setOverscroll()
}

/// When the scroll view scrolls, sync the preview if enabled in preferences
@objc private func scrollViewDidScroll() {
@objc private func scrollViewDidScroll() {
guard
preferences[Preference.syncEditorAndPreview],
let documentView = scrollView.documentView
Expand Down
3 changes: 2 additions & 1 deletion Pine/Extensions/Cocoa/NotificationCenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ extension NotificationCenter {
extension Notification.Name {
static let preferencesChanged = Notification.Name("preferencesChanged")
static let appearanceChanged = Notification.Name("appearanceChanged")
static let scrollViewScrolled = NSView.boundsDidChangeNotification
static let boundsDidChange = NSView.boundsDidChangeNotification
static let frameDidChange = NSView.frameDidChangeNotification
}
9 changes: 9 additions & 0 deletions Pine/Models/Preferences/Preferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum Preference {
static let syncEditorAndPreview = PreferenceKey<Bool>("syncEditorAndPreview", defaultValue: false)
static let showToolbar = PreferenceKey<Bool>("showToolbar", defaultValue: false)
static let showInvisibles = PreferenceKey<Bool>("showInvisibles", defaultValue: false)
static let scrollPastEnd = PreferenceKey<Bool>("scrollPastEnd", defaultValue: false)

// Font options
static let fontSize = PreferenceKey<CGFloat>("fontSize", defaultValue: 14)
Expand Down Expand Up @@ -79,6 +80,14 @@ class Preferences {
defaults.setValue(value, forKey: preferenceKey.key)
}

/// Given a boolean preference map, a key and value, set the value if found in the map
public func setFromBoolMap(_ map: BoolPreferenceMap, key: String, value: Bool) {
if let ext = map[key] {
self[ext] = value
NotificationCenter.send(.preferencesChanged)
}
}

// MARK: - Dynamic preferences

public var markdownExtensions: [MarkdownExtensions] {
Expand Down
68 changes: 52 additions & 16 deletions Pine/Views/MarkdownTextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,26 @@ import Cocoa

class MarkdownTextView: NSTextView {

private let CONTAINER_INSET: CGFloat = 10.0

private var overscroll: CGFloat = 0
private var needsRecompletion: Bool = false
private var partialAutocompleteWord: String?

private lazy var autocompletionTask = Debouncer(delay: 0, callback: {
[unowned self] in self.performCompletion()
})

override func keyDown(with event: NSEvent) {
if let singleCharacter = event.characters?.first, preferences[Preference.autoPairSyntax] {
self.pair(character: singleCharacter)
override var isContinuousSpellCheckingEnabled: Bool {
get {
return preferences[Preference.spellcheckEnabled]
}

super.keyDown(with: event)
}

override func insertText(_ string: Any, replacementRange: NSRange) {
super.insertText(string, replacementRange: replacementRange)
self.autocompletionTask.call()
set {}
}

override func didChangeText() {
super.didChangeText()

if self.needsRecompletion {
self.needsRecompletion = false
self.autocompletionTask.call()
}
override var textContainerOrigin: NSPoint {
return NSPoint(x: CONTAINER_INSET, y: CONTAINER_INSET)
}

override var rangeForUserCompletion: NSRange {
Expand All @@ -61,6 +54,33 @@ class MarkdownTextView: NSTextView {
return NSRange(location: location, length: cursorLocation - location)
}

override func viewDidMoveToWindow() {
// Setup notification for when scrollview frame changes
NotificationCenter.receive(.frameDidChange, instance: self, selector: #selector(setOverscroll))
}

override func keyDown(with event: NSEvent) {
if let singleCharacter = event.characters?.first, preferences[Preference.autoPairSyntax] {
self.pair(character: singleCharacter)
}

super.keyDown(with: event)
}

override func insertText(_ string: Any, replacementRange: NSRange) {
super.insertText(string, replacementRange: replacementRange)
self.autocompletionTask.call()
}

override func didChangeText() {
super.didChangeText()

if self.needsRecompletion {
self.needsRecompletion = false
self.autocompletionTask.call()
}
}

override func completions(
forPartialWordRange charRange: NSRange,
indexOfSelectedItem index: UnsafeMutablePointer<Int>
Expand Down Expand Up @@ -131,6 +151,22 @@ class MarkdownTextView: NSTextView {
super.paste(sender)
}

// MARK: - Public methods

@objc public func setOverscroll() {
guard
let font = self.font,
let scrollView = self.enclosingScrollView,
let lineHeight = layoutManager?.defaultLineHeight(for: font)
else { return }

let ratio: CGFloat = preferences[Preference.scrollPastEnd] ? 0.5 : 0

let inset = ratio * (scrollView.documentVisibleRect.height - lineHeight)

self.textContainerInset.height = max(floor(inset / 2), CONTAINER_INSET)
}

// MARK: - Private helper methods

private func pasteImages(_ images: [URL]) {
Expand Down
5 changes: 1 addition & 4 deletions Pine/Views/Preferences/DocumentStackView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ class DocumentStackView: NSStackView, PreferenceStackView {
// MARK: - Behavior preference actions

@objc func behaviorPreferenceChanged(_ sender: NSButton) {
if let ext = behaviourMap[sender.title] {
preferences[ext] = sender.value
NotificationCenter.send(.preferencesChanged)
}
preferences.setFromBoolMap(behaviourMap, key: sender.title, value: sender.value)
}

}
30 changes: 25 additions & 5 deletions Pine/Views/Preferences/EditorStackView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ class EditorStackView: NSStackView, PreferenceStackView, NSFontChanging {
"Show invisibles": Preference.showInvisibles
]

private let behaviourMap: BoolPreferenceMap = [
"Scroll past end": Preference.scrollPastEnd
]

private func getAppearanceArea() -> NSStackView {
let view = PreferencesStackView(name: "Appearance:")

Expand All @@ -26,6 +30,18 @@ class EditorStackView: NSStackView, PreferenceStackView, NSFontChanging {
return view
}

private func getBehaviorArea() -> NSStackView {
let view = PreferencesStackView(name: "Behavior:")

view.addBooleanArea(
target: self,
using: behaviourMap,
selector: #selector(behaviorPreferenceChanged)
)

return view
}

private func getFontArea() -> NSStackView {
let view = PreferencesStackView(name: "Font:")

Expand All @@ -44,17 +60,21 @@ class EditorStackView: NSStackView, PreferenceStackView, NSFontChanging {
public func getViews() -> [NSView] {
return [
getAppearanceArea(),
getBehaviorArea(),
getFontArea()
]
}

// MARK: - Behavior preference actions
// MARK: - Appearance preference actions

@objc func appearancePreferenceChanged(_ sender: NSButton) {
if let ext = appearanceMap[sender.title] {
preferences[ext] = sender.value
NotificationCenter.send(.preferencesChanged)
}
preferences.setFromBoolMap(appearanceMap, key: sender.title, value: sender.value)
}

// MARK: - Behavior preference actions

@objc func behaviorPreferenceChanged(_ sender: NSButton) {
preferences.setFromBoolMap(behaviourMap, key: sender.title, value: sender.value)
}

// MARK: - Font preference actions
Expand Down
15 changes: 3 additions & 12 deletions Pine/Views/Preferences/MarkdownStackView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,28 +95,19 @@ class MarkdownStackView: NSStackView, PreferenceStackView {
// MARK: - Behavior preference actions

@objc func behaviourPreferenceChanged(_ sender: NSButton) {
if let ext = behaviourMap[sender.title] {
preferences[ext] = sender.value
NotificationCenter.send(.preferencesChanged)
}
preferences.setFromBoolMap(behaviourMap, key: sender.title, value: sender.value)
}

// MARK: - Autocomplete preference actions

@objc func autocompletePreferenceChanged(_ sender: NSButton) {
if let ext = autocompleteMap[sender.title] {
preferences[ext] = sender.value
NotificationCenter.send(.preferencesChanged)
}
preferences.setFromBoolMap(autocompleteMap, key: sender.title, value: sender.value)
}

// MARK: - Markdown extension preference actions

@objc func extensionPreferenceChanged(_ sender: NSButton) {
if let ext = extensionsMap[sender.title] {
preferences[ext] = sender.value
NotificationCenter.send(.preferencesChanged)
}
preferences.setFromBoolMap(extensionsMap, key: sender.title, value: sender.value)
}

// MARK: - Default application preference actions
Expand Down
15 changes: 3 additions & 12 deletions Pine/Views/Preferences/UIStackView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,28 +105,19 @@ class UIStackView: NSStackView, PreferenceStackView {
}

@objc func appearancePreferenceChanged(_ sender: NSButton) {
if let ext = appearanceMap[sender.title] {
preferences[ext] = sender.value
NotificationCenter.send(.preferencesChanged)
}
preferences.setFromBoolMap(appearanceMap, key: sender.title, value: sender.value)
}

// MARK: - Window preference actions

@objc func windowPreferenceChanged(_ sender: NSButton) {
if let ext = windowMap[sender.title] {
preferences[ext] = sender.value
NotificationCenter.send(.preferencesChanged)
}
preferences.setFromBoolMap(windowMap, key: sender.title, value: sender.value)
}

// MARK: - Behavior preference actions

@objc func behaviorPreferenceChanged(_ sender: NSButton) {
if let ext = behaviorMap[sender.title] {
preferences[ext] = sender.value
NotificationCenter.send(.preferencesChanged)
}
preferences.setFromBoolMap(behaviorMap, key: sender.title, value: sender.value)
}

}

0 comments on commit aadd8ac

Please sign in to comment.