This commit is contained in:
Corey Johnson
2011-10-26 11:10:52 -07:00
parent 80d6222809
commit e64a0e64a1
16 changed files with 223 additions and 364 deletions

View File

@@ -17,29 +17,22 @@
}
// Overridden
- (void)sendEvent:(NSEvent *)event {
switch ([event type]) {
case NSKeyDown:
{
BOOL handeled = NO;
id controller = [[self keyWindow] windowController];
// The keyWindow could be a Cocoa Dialog or something, ignore them.
if ([controller isKindOfClass:[AtomController class]]) {
handeled = [controller handleKeyEvent:event];
}
if (!handeled) {
[super sendEvent:event];
}
}
break;
default:
[super sendEvent:event];
break;
}
}
//- (void)sendEvent:(NSEvent *)event {
// if ([event type] == NSKeyDown) {
// BOOL handeled = NO;
// id controller = [[self keyWindow] windowController];
//
// // The keyWindow could be a Cocoa Dialog or something, ignore that.
// if ([controller isKindOfClass:[AtomController class]]) {
// handeled = [controller handleKeyEvent:event];
// }
//
// if (!handeled) [super sendEvent:event];
// }
// else {
// [super sendEvent:event];
// }
//}
// AppDelegate
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification {

View File

@@ -20,10 +20,10 @@
[jscocoa unlinkAllReferences];
[jscocoa garbageCollect];
[jscocoa release]; jscocoa = nil;
[webView release];
[URL release];
[super dealloc];
}
@@ -37,7 +37,7 @@
[super windowDidLoad];
[webView setUIDelegate:self];
[self setShouldCascadeWindows:YES];
[self setWindowFrameAutosaveName:@"atomController"];
@@ -48,14 +48,19 @@
jscocoa = [[JSCocoa alloc] initWithGlobalContext:[[webView mainFrame] globalContext]];
[jscocoa setObject:self withName:@"atomController"];
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
NSString *requirePath = [resourcePath stringByAppendingString:@"/src/require.js"];
[jscocoa evalJSFile:requirePath];
// NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
// NSString *requirePath = [resourcePath stringByAppendingString:@"/src/require.js"];
// [jscocoa evalJSFile:requirePath];
NSURL *resourceURL = [[NSBundle mainBundle] resourceURL];
NSURL *indexURL = [resourceURL URLByAppendingPathComponent:@"index.html"];
NSURLRequest *request = [NSURLRequest requestWithURL:indexURL];
NSURLRequest *request = [NSURLRequest requestWithURL:indexURL];
[[webView mainFrame] loadRequest:request];
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
NSString *requirePath = [resourcePath stringByAppendingString:@"/src/watcher.js"];
[jscocoa evalJSFile:requirePath];
}
}
@@ -72,7 +77,7 @@
// WebUIDelegate Protocol
- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems {
return [NSArray array];
return defaultMenuItems;
}

View File

@@ -1,4 +1,4 @@
/* =============================================================================
/* =============================================================================
FILE: UKMainThreadProxy.h
PROJECT: UKMainThreadProxy

24
docs/sample-conf.coffee Normal file
View File

@@ -0,0 +1,24 @@
# ~/.atomicity/settings.coffee
# ----------------------------
editor:
tabSize: 2
spaces: true
# ~/.atomicity/keybindings.coffee
app:
"cmd-q": (app) -> app.quit()
"cmd-q": "quit" # optional way?
editor:
"ctrl-p": (editor) -> editor.moveUp()
"ctrl-a": (editor) ->
position = editor.cursorPosition()
position.column = 0
editor.setCursorPosition(position)
tree:
"cmd-ctrl-n": (tree) -> tree.toggle()
window:
'Command-O' : @open
'Command-Ctrl-K' : @showConsole

View File

@@ -65,12 +65,12 @@
</body>
<script>
//require('startup');
window.onerror = function(message, url, lineNumber) {
// Any error will popup the console
WindowController.webView.inspector.showConsole(true);
atomController.webView.inspector.showConsole(true);
}
require('startup');
</script>
</html>

View File

@@ -1,13 +1,18 @@
_ = require 'underscore'
File = require 'fs'
Window = require 'window'
KeyBinder = require 'key-binder'
require 'window'
module.exports =
class App
@root: OSX.NSBundle.mainBundle.resourcePath
@start: ->
@window = new Window
controller : AtomController
path : localStorage.lastOpenedPath ? File.workingDirectory()
@startup: ->
KeyBinder.register "app", @
window.startup()
KeyBinder.load "#{@root}/static/key-bindings.coffee"
KeyBinder.load "~/.atomicity/key-bindings.coffee"
@quit: ->
OSX.NSApp.terminate OSX.NSApp

View File

@@ -1,34 +0,0 @@
module.exports =
class Chrome
# path - Optional. The String path to the file to base it on.
@newWindow: (path) ->
c = OSX.AtomWindowController.alloc.initWithWindowNibName "AtomWindow"
c.window
c.window.makeKeyAndOrderFront null
# Returns null or a file path.
@openPanel: ->
panel = OSX.NSOpenPanel.openPanel
panel.setCanChooseDirectories true
if panel.runModal isnt OSX.NSFileHandlingPanelOKButton
return null
filename = panel.filenames.lastObject
localStorage.lastOpenedPath = filename
filename
@openURL: (url) ->
window.location = url
App = require 'app'
App.activeWindow.setTitle _.last url.replace(/\/$/,'').split '/'
# Returns null or a file path.
@savePanel: ->
panel = OSX.NSSavePanel.savePanel
if panel.runModal isnt OSX.NSFileHandlingPanelOKButton
return null
panel.filenames.lastObject
@writeToPasteboard: (text) ->
pb = OSX.NSPasteboard.generalPasteboard
pb.declareTypes_owner [OSX.NSStringPboardType], null
pb.setString_forType text, OSX.NSStringPboardType

124
src/key-binder.coffee Normal file
View File

@@ -0,0 +1,124 @@
_ = require 'underscore'
fs = require 'fs'
Watcher = require 'watcher'
{CoffeeScript} = require 'coffee-script'
module.exports =
class KeyBinder
@bindings: {}
@scopes: {}
@register: (name, scope) ->
@scopes[name] = scope
@load: (path) ->
try
Watcher.watch path, ->
# Should we keep track of which file bindings are associated with? That
# way we could clear bindings when the file is changed or deleted. I
# think the answer is yes, but I don't want to do this right now.
console.log "#{@name}: Reloading #{path}"
@load path
json = CoffeeScript.eval "return " + (fs.read path)
for scopeName, bindings of json
@create scopeName, binding, method for binding, method of bindings
catch error
console.error "#{@class}: Could not load key bindings at `#{path}`. #{error}"
@create: (scope, binding, method) ->
if typeof scope is "string"
throw "#{@name}: Unknown scope `#{scope}`" unless @scopes[scope]
scope = @scopes[scope]
callback = if _.isFunction method
-> method scope
else if scope[method]
-> scope[method] scope
else
throw "#{@name}: '#{method}' not found found in scope #{scope}"
callbacks = @bindings[@bindingParser binding] ?= []
callbacks.push callback
@handleEvent: (event) ->
keys = []
keys.push @modifierKeys.command if event.modifierFlags & OSX.NSCommandKeyMask
keys.push @modifierKeys.shift if event.modifierFlags & OSX.NSShiftKeyMask
keys.push @modifierKeys.control if event.modifierFlags & OSX.NSControlKeyMask
keys.push @modifierKeys.alt if event.modifierFlags & OSX.NSAlternateKeyMask
keys.push event.charactersIgnoringModifiers.toLowerCase().charCodeAt 0
binding = keys.sort().join "-"
callbacks = @bindings[binding]
return false if not callbacks
callback() for callback in callbacks
true
@bindingParser: (binding) ->
keys = binding.trim().split '-'
modifiers = []
key = null
for k in keys
k = k.toLowerCase()
if @modifierKeys[k]
modifiers.push @modifierKeys[k]
else if key
throw "#{@name}: #{binding} specifies TWO keys, we don't handle that yet."
else if @namedKeys[k]
key = @namedKeys[k]
else if k.length > 1
throw "#{@name}: #{binding} uses an unknown key #{k}."
else
key = k.charCodeAt 0
modifiers.concat(key).sort().join "-"
@modifierKeys:
'': 16
shift: 16
alt: 18
option: 18
'': 18
control: 17
ctrl: 17
command: 91
cmd: 91
'': 91
@namedKeys:
backspace: 8
tab: 9
clear: 12
enter: 13
return: 13
esc: 27
escape: 27
space: 32
left: 37
up: 38
right: 39
down: 40
del: 46
delete: 46
home: 36
end: 35
pageup: 33
pagedown: 34
',': 188
'.': 190
'/': 191
'`': 192
'-': 189
'=': 187
';': 186
'\'': 222
'[': 219
']': 221
'\\': 220

View File

@@ -1,95 +0,0 @@
_ = require 'underscore'
modifierKeys =
'': 16
shift: 16
alt: 18
option: 18
'': 18
control: 17
ctrl: 17
command: 91
cmd: 91
'': 91
namedKeys =
backspace: 8
tab: 9
clear: 12
enter: 13
return: 13
esc: 27
escape: 27
space: 32
left: 37
up: 38
right: 39
down: 40
del: 46
delete: 46
home: 36
end: 35
pageup: 33
pagedown: 34
',': 188
'.': 190
'/': 191
'`': 192
'-': 189
'=': 187
';': 186
'\'': 222
'[': 219
']': 221
'\\': 220
bindings = {}
shortcutParser = (shortcut) ->
keys = shortcut.trim().split '-'
modifiers = []
key = null
for k in keys
k = k.toLowerCase()
if modifierKeys[k]
modifiers.push modifierKeys[k]
else if key
throw "THIS KEYBINDING #{shortcut} specifies TWO keys, we don't handle that yet."
else if namedKeys[k]
key = namedKeys[k]
else if k.length > 1
throw "THIS KEYBINDING #{shortcut} uses an unknown key #{k}."
else
key = k.charCodeAt 0
modifiers.concat(key).sort().join "-"
exports.bindKey = (scope, shortcut, method) ->
callback = if _.isFunction method
-> method.apply scope
else if scope[method]
-> scope[method]()
else
console.error "keymap: no '#{method}' method found"
-> console.error "keymap: #{shortcut} failed to bind"
callbacks = bindings[shortcutParser shortcut] ?= []
callbacks.push callback
window.handleKeyEvent = (event) ->
keys = []
keys.push modifierKeys.command if event.modifierFlags & OSX.NSCommandKeyMask
keys.push modifierKeys.shift if event.modifierFlags & OSX.NSShiftKeyMask
keys.push modifierKeys.control if event.modifierFlags & OSX.NSControlKeyMask
keys.push modifierKeys.alt if event.modifierFlags & OSX.NSAlternateKeyMask
keys.push event.charactersIgnoringModifiers.charCodeAt 0
shortcut = keys.sort().join "-"
callbacks = bindings[shortcut]
return false if not callbacks
callback() for callback in callbacks
true

View File

@@ -1,44 +0,0 @@
$ = require 'jquery'
module.exports =
class Pane
position: null
html: null
showing: false
constructor: (@window) ->
add: ->
verticalDiv = $('#app-vertical')
horizontalDiv = $('#app-horizontal')
el = $ "<div>"
el.addClass "pane " + @position
el.append @html
switch @position
when 'main'
$('.main').replaceWith el
when 'top'
verticalDiv.prepend el
when 'left'
horizontalDiv.prepend el
when 'bottom'
verticalDiv.append el
when 'right'
horizontalDiv.append el
else
throw "I DON'T KNOW HOW TO DEAL WITH #{@position}"
toggle: ->
if @showing
@html.parent().detach()
else
@add this
@showing = not @showing
# Override these in your subclass
initialize: ->

View File

@@ -1,43 +0,0 @@
{bindKey} = require 'keybinder'
module.exports =
class Plugin
constructor: (@window) ->
console.log "Loaded Plugin: " + @.constructor.name
for shortcut, method of @keymap()
bindKey @, shortcut, method
# Called after all plugins are loaded
load: ->
pane: ->
keymap: ->
storageNamespace: -> @.constructor.name
get: (key, defaultValue) ->
try
object = JSON.parse(localStorage[@storageNamespace()] ? "{}")
catch error
error.message += "\nGetting #{key}"
console.log(error)
object[key] ? defaultValue
set: (key, value) ->
try
object = JSON.parse(localStorage[@storageNamespace()] ? "{}")
catch error
error.message += "\nSetting #{key}: #{value}"
console.log(error)
# Putting data in
if value == undefined
delete object[key]
else
object[key] = value
localStorage[@storageNamespace()] = JSON.stringify(object)

View File

@@ -1,3 +1,3 @@
# Like sands through the hourglass, so are the days of our lives.
App = require 'app'
App.start()
App.startup()

View File

@@ -1,7 +0,0 @@
# commonjs system module
# http://ringojs.org/api/v0.8/system/
module.exports =
# An object containing our environment variables.
env: ->
OSX.NSProcess.processInfo.environment

View File

@@ -1,4 +1,4 @@
module.exports =
#module.exports =
class Watcher
@watchedPaths: {}
@@ -18,8 +18,7 @@ class Watcher
(@watchedPaths[path] ?= []).push callback
# Used to unwatch a path
callback
callback # Handy for anonymous functions.
@unwatch: (path, callback=null) ->
return unless @watchedPaths[path]
@@ -30,15 +29,22 @@ class Watcher
@queue.removePathFromQueue path
# Delegate method for AAWatcher
change the name of this method
@watcher_receivedNotification_forPath = (queue, notification, path) =>
callbacks = @watchedPaths[path]
switch notification
when "UKFileWatcherRenameNotification"
switch notification.toString()
when "UKKQueueFileRenamedNotification"
raise "Doesn't handle this yet"
when "UKFileWatcherDeleteNotification"
when "UKKQueueFileDeletedNotification"
@watchedPaths[path] = null
@queue.removePathFromQueue path
when "UKKQueueFileWrittenToNotification"
callback notification, path, callback for callback in callbacks
when "UKKQueueFileAttributesChangedNotification"
# Just ignore this
else
console.error "I HAVE NO IDEA WHEN #{notification} IS TRIGGERED"
Watcher.watch "~/tmp/what.txt", ->
OSX.NSLog "HI"
callback notification, path, callback for callback in callbacks

View File

@@ -1,98 +1,21 @@
$ = require 'jquery'
File = require 'fs'
Chrome = require 'chrome'
KeyBinder = require 'key-binder'
{bindKey} = require 'keybinder'
oop = require "pilot/oop"
{EventEmitter} = require "pilot/event_emitter"
windowAdditions =
extensions: []
module.exports =
class Window
controller: null
startup: ->
KeyBinder.register "window", window
nswindow: null
@path = localStorage.lastOpenedPath ? File.workingDirectory()
@appPath = OSX.NSBundle.mainBundle.resourcePath
panes: []
keymap: ->
'Command-N' : @new
'Command-O' : @open
'Command-Shift-O' : @openURL
'Command-Ctrl-K' : @showConsole
'Command-Ctrl-M' : @reload
constructor: (options={}) ->
oop.implement @, EventEmitter
for option, value of options
@[option] = value
for shortcut, method of @keymap()
bindKey @, shortcut, method
@nswindow = @controller?.window
@loadPlugins()
@._emit "loaded"
loadPlugins: ->
@plugins = []
# Ewwww, don't do this
App = require 'app'
for pluginPath in File.list(App.root + "/plugins")
if File.isDirectory pluginPath
try
plugin = require pluginPath
@plugins.push new plugin(@)
catch error
console.warn "Plugin Failed: #{File.base pluginPath}"
console.warn error
@open @path if @path?
# After all the plugins are created, load them.
for plugin in @plugins
try
plugin.load()
catch error
console.warn "Plugin Loading Failed: #{plugin.constructor.name}"
console.warn error
reload: ->
Chrome.newWindow()
@controller.close
inspector: ->
@_inspector ?= WindowController.webView.inspector
new: ->
Chrome.newWindow()
handleKeyEvent: ->
KeyBinder.handleEvent.apply KeyBinder, arguments
showConsole: ->
@inspector().showConsole(1)
atomController.webView.inspector.showConsole true
title: ->
@nswindow.title
setTitle: (title) ->
@nswindow.title = title
# Do these get moved into document?
isDirty: ->
@nswindow.isDocumentEdited()
# Set the active window's dirty status.
setDirty: (bool) ->
@nswindow.setDocumentEdited bool
open: (path) ->
@_emit 'open', { filename: path }
close: (path) ->
@_emit 'close', { filename: path }
openURL: (url) ->
if url = prompt "Enter URL:"
Chrome = require 'app'
Chrome.openURL url
for key, value of windowAdditions
raise "DOMWindow already has a key named #{key}" if window[key]
window[key] = value

View File

@@ -0,0 +1,2 @@
app:
"cmd-q": (app) -> app.quit()