26
Enhancing Your Workflow with Xcode Source Editor Extensions By: Jesse Black Software Engineer stable|kernel [email protected]

Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Embed Size (px)

Citation preview

Page 1: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Enhancing Your Workflow with Xcode Source Editor Extensions

By: Jesse Black Software Engineer stable|[email protected]

Page 2: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

@stablekernel

Hi, I’m Jesse Black.

• Programming for over eight years • Created a Mac App for my family business • Worked for 3 years with Gramercy Consultants developing iOS and Android apps • Working for stable|kernel for the past 3 years developing iOS apps, Android apps

and their supporting APIs

Page 3: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

We’re stable|kernel.

stable|kernel is an Atlanta-based mobile development company to craft smartly-designed mobile applications that connect brands directly with their users.

Page 4: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Enhancing Your Workflow with Xcode Source Editor Extensions

@stablekernel

Overview

Mac App Extensions Xcode Source Editor Extensions Demo: Create Source Editor Extension and debugging it XC Classes Example: JSON formatter Demo: JSON formatter in action

Page 5: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Mac App Extensions

@stablekernel

• Mac App Extensions

• Affect the user experience of other apps

• Need to be lightweight and run fast

• Require user interaction in order to be run

• Distribute via host app

Page 6: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Why use Xcode Source Editor Extensions

@stablekernel

• Less context switching

• It is too fun to customize your workflow

Page 7: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Xcode Source Editor Extensions

@stablekernel

• Differences with general Mac App Extensions

• Extensions are installed by just putting the host application in your applications folder

• Only works with one type of target application, which is Xcode

• Doesn’t have UI

Page 8: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Xcode Source Editor Extensions

@stablekernel

• Allows you to add custom commands under Xcode’s Editor menu

• Commands can manipulate text and text selections

• Users can put bind keyboard shortcuts to invoke your commands

Page 9: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Limitations to Xcode Source Editor Extensions

@stablekernel

• Can only start with user interaction

• Lack of ability to integrate into the build process and archive process. It is for modifying source code while it is being edited.

Page 10: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Expectations of Xcode Source Editor Extensions

@stablekernel

• Fast start up

• Fast execution

• Security and Stability

Page 11: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Demo

@stablekernel

Overview

Create Source Editor Extension How to install How to debug How to uninstall

Page 12: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Defining Commands

@stablekernel

• Command Identifier

• Class Name

• Command Name

Commands can be defined in the Extension’s plist or by supplying a dictionary at runtime. Commands provided at runtime override commands defined in the plist.

Page 13: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

XC Source Editor Extension

@stablekernel

func extensionDidFinishLaunching() {}

var commandDefinitions: [[XCSourceEditorCommandDefinitionKey: Any]] {}

Page 14: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

XC Source Editor Command

@stablekernel

func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void {

Page 15: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

XC Source Editor Command

@stablekernel

• Modify text, text selection

• Exit early with an error message that is displayed in Xcode

Page 16: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

XC Source Editor Command Invocation

@stablekernel

• Encapsulates all details needed to fulfill the user’s request • contentUTI • usesTabsForIndentation • indentationWidth • tabWidth • buffer

Page 17: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

XC Source Text Buffer

@stablekernel

• completeBuffer • lines • selections

• defined in terms of lines and columns

Page 18: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Example: JSON formatter

@stablekernel

• Define minify and prettify commands • Implement XCSourceEditorCommand’s perform method

• Validate requirements for command • Get first text selection • Return error if selected text isn’t valid JSON • Use JSONSerialization class to format text • Replace selected text

Page 19: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

XCSourceEditorExtension

@stablekernel

var commandDefinitions: [[XCSourceEditorCommandDefinitionKey: Any]] { return [ [ .classNameKey: "JeSON.SourceEditorCommand", .identifierKey: JeSONInvocation.Minify.rawValue, .nameKey: "Minify" ], [ .classNameKey: "JeSON.SourceEditorCommand", .identifierKey: JeSONInvocation.Prettify.rawValue, .nameKey: "Prettify" ], ] }

Page 20: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

XCSourceEditorExtension

@stablekernel

enum JeSONInvocation: String { case Prettify = "com.jesseblack.HelloWorldProject.JeSON.Prettify" case Minify = "com.jesseblack.HelloWorldProject.JeSON.Minify" }

Page 21: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

@stablekernel

func textAtSelectionIndex(_ at: Int, buffer: XCSourceTextBuffer) -> String { let textRange = buffer.selections[at] as! XCSourceTextRange let selectionLines = buffer.lines.enumerated().filter { (offset, element) -> Bool in return offset >= textRange.start.line && offset <= textRange.end.line }.map { return $1 } return selectionLines.enumerated().reduce("") { (result, enumeration) -> String in let line = enumeration.element as! String if enumeration.offset == 0 && enumeration.offset == selectionLines.count - 1 { let startIndex = line.index(line.startIndex, offsetBy: textRange.start.column) let endIndex = line.index(line.startIndex, offsetBy: textRange.end.column + 1)

return result + line.substring(with: startIndex..<endIndex) } else if enumeration.offset == 0 { let startIndex = line.index(line.startIndex, offsetBy: textRange.start.column) return result + line.substring(from: startIndex) } else if enumeration.offset == selectionLines.count - 1 { let endIndex = line.index(line.startIndex, offsetBy: textRange.end.column + 1) return result + line.substring(to: endIndex) } return result + line } }

Page 22: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

@stablekernel

func replaceTextAtSelectionIndex(_ at: Int, replacementText: String, buffer: XCSourceTextBuffer) { let textRange = buffer.selections[at] as! XCSourceTextRange

let lastLine = buffer.lines[textRange.end.line] as! String let endIndex = lastLine.index(lastLine.startIndex, offsetBy: textRange.end.column+1) let suffix = lastLine.substring(from: endIndex) let firstLine = buffer.lines[textRange.start.line] as! String let startIndex = firstLine.index(firstLine.startIndex, offsetBy: textRange.start.column) let prefix = firstLine.substring(to: startIndex) let range = NSMakeRange(textRange.start.line, textRange.end.line - textRange.start.line + 1) buffer.lines.removeObjects(in: range) buffer.lines.insert(prefix+replacementText+suffix, at: textRange.start.line) let newRange = XCSourceTextRange(start: textRange.start, end: textRange.start) buffer.selections.setArray([newRange]) }

Page 23: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Performing the command

@stablekernel

func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void { guard let jeSONInvocation = JeSONInvocation(rawValue: invocation.commandIdentifier) else { let errorInfo = [NSLocalizedDescriptionKey: "Command not recognized"] completionHandler(NSError(domain: "", code: 0, userInfo: errorInfo)) return } let buffer = invocation.buffer guard buffer.selections.count == 1 else { let errorInfo = [NSLocalizedDescriptionKey: "Command only handles 1 selection at a time"] completionHandler(NSError(domain: "", code: 0, userInfo: errorInfo)) return }

Page 24: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Performing the command

@stablekernel

// perform continued

let selectedText = textAtSelectionIndex(0, buffer: buffer) let data = selectedText.data(using: .utf8) do { let jsonObject = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions()) switch jeSONInvocation { case .Minify: let miniData = try! JSONSerialization.data(withJSONObject: jsonObject, options: JSONSerialization.WritingOptions()) let string = String.init(data: miniData, encoding: .utf8)! replaceTextAtSelectionIndex(0, replacementText: string, buffer: buffer) case .Prettify: let miniData = try! JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) let string = String.init(data: miniData, encoding: .utf8)! replaceTextAtSelectionIndex(0, replacementText: string, buffer: buffer) } } catch { completionHandler(error) }

completionHandler(nil) }

Page 25: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

JSON Formatter Demo

@stablekernel

Overview

See all the hard work pay off

Page 26: Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions

Questions?

Business Inquiries:Sarah WoodwardDirector of Business [email protected]

Jesse BlackSoftware [email protected]@JesseBlack82

http://www.slideshare.net/stablekernel https://github.com/JesseBlack82/HelloExtensions