godbout / kindaVim.docs

Ultimate Vim Mode for macOS
https://kindavim.app
614 stars 4 forks source link

add `~` #30

Closed godbout closed 2 years ago

godbout commented 2 years ago

see #26 6.

godbout commented 2 years ago

plus from tthkbw:

I use ~ a lot, usually just by itself. Since it moves the cursor to the right, if I want to all-caps something, I usually just repeat the single key. However, I occasionally make use of visual mode selections to change case (this is usually because I have copied something long that is all caps). I rarely used count in Vim (takes to long to figure out what the count should be), but sometimes they are quite useful, particularly in macros. Similarly, I don't often use 'g' movements in Vim.

With particular respect to usage in kindaVim, I use ~ to fix cases where I missed timing on the shift key and ended up with a word that was supposed to be capitalized but was not. It is a big timesaver, keystroke saver, since I don't need to change back and forth between Normal and insert modes.

godbout commented 2 years ago

let's do a little bit of open source

godbout commented 2 years ago

Accessibility Strategy Normal Mode ~ done:

public func tilde(times count: Int? = 1, on element: AccessibilityTextElement?, pgR: Bool) -> AccessibilityTextElement? {
        guard let element = element else { return nil }
        guard element.isNotEmpty else { return element }
        var newElement = element

        var listOfCharactersCased = ""
        var location = element.caretLocation

        for _ in 1...(count ?? 1) {
            guard location <= element.currentFileLine.endLimit, let characterAtLocation = element.characterForCharacter(at: location) else { break }

            let characterCased = characterAtLocation.isLowercase ? characterAtLocation.uppercased() : characterAtLocation.lowercased()
            listOfCharactersCased.append(characterCased)

            location += element.characterLengthForCharacter(at: location)
        }

        newElement.selectedLength = listOfCharactersCased.utf16.count
        newElement.selectedText = listOfCharactersCased

        // coz needs to block cursor the character after the move
        _ = AccessibilityTextElementAdaptor.toAXFocusedElement(from: newElement)
        guard var updatedElement = AccessibilityTextElementAdaptor.fromAXFocusedElement() else { return nil }

        guard updatedElement.caretLocation <= updatedElement.currentFileLine.endLimit else {
            updatedElement.caretLocation = updatedElement.currentFileLine.endLimit
            updatedElement.selectedLength = updatedElement.characterLength
            updatedElement.selectedText = nil

            return updatedElement
        }

        updatedElement.selectedLength = updatedElement.characterLength
        updatedElement.selectedText = nil

        return updatedElement
    }
godbout commented 2 years ago

the tests (UI coz need block cursor repositioning after the move):

import XCTest
@testable import AccessibilityStrategy

class ASUI_NM_tilde_Tests: ASUI_NM_BaseTests {

    private func applyMoveBeingTested(times count: Int = 1, pgR: Bool = false) -> AccessibilityTextElement? {
        return applyMove { asNormalMode.tilde(times: count, on: $0, pgR: pgR) }
    }

}

// count
extension ASUI_NM_tilde_Tests {

    func test_that_it_implements_the_count_system() {
        let textInAXFocusedElement = "we goNNa moVe in tHere with count 🈹️ awww"
        app.textFields.firstMatch.tap()
        app.textFields.firstMatch.typeText(textInAXFocusedElement)

        applyMove { asNormalMode.l(on: $0) }
        applyMove { asNormalMode.F(to: "g", on: $0) }
        let accessibilityElement = applyMoveBeingTested(times: 10)

        XCTAssertEqual(accessibilityElement?.fileText.value, "we GOnnA MOvE in tHere with count 🈹️ awww")
        XCTAssertEqual(accessibilityElement?.caretLocation, 13)
        XCTAssertEqual(accessibilityElement?.selectedLength, 1)
        XCTAssertEqual(accessibilityElement?.selectedText, " ")
    }

    func test_that_when_the_count_is_too_high_it_changes_the_characters_case_until_the_end_of_the_FileLine() {
        let textInAXFocusedElement = """
we goNNa moVe in tHere with count 🈹️ awww
and one more line
"""
        app.textViews.firstMatch.tap()
        app.textViews.firstMatch.typeText(textInAXFocusedElement)

        applyMove { asNormalMode.gg(on: $0) }
        applyMove { asNormalMode.w(on: $0) }
        let accessibilityElement = applyMoveBeingTested(times: 69)

        XCTAssertEqual(accessibilityElement?.fileText.value, """
we GOnnA MOvE IN ThERE WITH COUNT 🈹️ AWWW
and one more line
"""
)
        XCTAssertEqual(accessibilityElement?.caretLocation, 41)
        XCTAssertEqual(accessibilityElement?.selectedLength, 1)
        XCTAssertEqual(accessibilityElement?.selectedText, "W")
    }

}

// Both
extension ASUI_NM_tilde_Tests {

    func test_that_in_normal_setting_it_replaces_a_lowercase_character_by_an_uppercase_one() {
        let textInAXFocusedElement = "gonna replace one of those😂️letters..."
        app.textFields.firstMatch.tap()
        app.textFields.firstMatch.typeText(textInAXFocusedElement)

        applyMove { asNormalMode.B(on: $0) }
        applyMove { asNormalMode.e(on: $0) }
        let accessibilityElement = applyMoveBeingTested()

        XCTAssertEqual(accessibilityElement?.fileText.value, "gonna replace one of thosE😂️letters...")
        XCTAssertEqual(accessibilityElement?.caretLocation, 26)
        XCTAssertEqual(accessibilityElement?.selectedLength, 3)
    }

    func test_that_in_normal_setting_it_replaces_an_uppercase_character_by_a_lowercase_one() {
        let textInAXFocusedElement = "gonna replace one of thosE😂️letters..."
        app.textFields.firstMatch.tap()
        app.textFields.firstMatch.typeText(textInAXFocusedElement)

        applyMove { asNormalMode.B(on: $0) }
        applyMove { asNormalMode.e(on: $0) }
        let accessibilityElement = applyMoveBeingTested()

        XCTAssertEqual(accessibilityElement?.fileText.value, "gonna replace one of those😂️letters...")
        XCTAssertEqual(accessibilityElement?.caretLocation, 26)
        XCTAssertEqual(accessibilityElement?.selectedLength, 3)
    }

}
godbout commented 2 years ago

actually all the tests are open source and available here: https://github.com/godbout/AccessibilityStrategyTestApp/blob/master/AccessibilityStrategyTestAppUITests/AccessibilityStrategyUITests/AccessibilityStrategyNormalMode/Moves/ASUI_NM_%7E_Tests.swift

godbout commented 2 years ago

shit. forgot to handle the PGR Mode for that one ☹️ back to it i guess.

godbout commented 2 years ago

looks fun tho

https://user-images.githubusercontent.com/121373/147880615-c7e72f25-8d46-49a2-9680-e7274e0d0030.mov

godbout commented 2 years ago

final version 🙈️🙈️🙈️

public func tilde(times count: Int? = 1, on element: AccessibilityTextElement?, pgR: Bool) -> AccessibilityTextElement? {
        guard let element = element else { return nil }
        guard element.isNotEmpty else { return element }
        var newElement = element

        var listOfCharactersCased = ""
        var location = element.caretLocation

        for _ in 1...(count ?? 1) {
            guard location <= element.currentFileLine.endLimit, let characterAtLocation = element.characterForCharacter(at: location) else { break }

            let characterCased = characterAtLocation.isLowercase ? characterAtLocation.uppercased() : characterAtLocation.lowercased()
            listOfCharactersCased.append(characterCased)

            location += element.characterLengthForCharacter(at: location)
        }

        newElement.selectedLength = listOfCharactersCased.utf16.count
        newElement.selectedText = listOfCharactersCased

        _ = AccessibilityTextElementAdaptor.toAXFocusedElement(from: newElement)
        pgR == true ? applyPGRMagicDelete(checkPropagationWith: newElement.fileText.value) : ()
        guard let updatedElement = AccessibilityTextElementAdaptor.fromAXFocusedElement() else { return nil }
        pgR == true ? applyPGRMagicPaste(checkPropagationWith: updatedElement.fileText.value, textToPaste: listOfCharactersCased) : ()
        guard var updatedElement = AccessibilityTextElementAdaptor.fromAXFocusedElement() else { return nil }

        guard updatedElement.caretLocation <= updatedElement.currentFileLine.endLimit else {
            updatedElement.caretLocation = updatedElement.currentFileLine.endLimit
            updatedElement.selectedLength = updatedElement.characterLength
            updatedElement.selectedText = nil

            return updatedElement
        }

        updatedElement.selectedLength = updatedElement.characterLength
        updatedElement.selectedText = nil

        return updatedElement
    }

the fucking browsers and Catalyst apps. what a fucking nightmare.

godbout commented 2 years ago

THAT IS FREAKING FAST!!! (and also doing some extra work with r.)

https://user-images.githubusercontent.com/121373/147904676-f71d8779-6ec1-4208-97c3-f2276e74ef4f.mp4

godbout commented 2 years ago

done in 1b18.