Merge remote-tracking branch 'origin/dev' into markers

Conflicts:
	src/app/editor.coffee
This commit is contained in:
Kevin Sawicki & Nathan Sobo
2013-02-05 16:07:05 -07:00
45 changed files with 502 additions and 167 deletions

7
.atom/config.cson Normal file
View File

@@ -0,0 +1,7 @@
'editor':
'fontSize': 16
'core':
'themes': [
'atom-dark-ui'
'atom-dark-syntax'
]

View File

@@ -1,11 +0,0 @@
{
"editor": {
"fontSize": 16
},
"core": {
"themes": [
"atom-dark-ui",
"atom-dark-syntax"
]
}
}

1
.atom/packages/README.md Normal file
View File

@@ -0,0 +1 @@
All packages in this directory will be automatically loaded

1
.pairs
View File

@@ -5,6 +5,7 @@ pairs:
ks: Kevin Sawicki; kevin
jc: Jerry Cheung; jerry
bl: Brian Lopez; brian
jp: Justin Palmer; justin
email:
domain: github.com
#global: true

View File

@@ -9,8 +9,8 @@ gutter.
You can change the background color using the following CSS:
```css
.editor.is-focused .line.cursor-line,
.editor.is-focused .line-number.cursor-line {
.editor .line.cursor-line,
.editor .line-number.cursor-line {
background-color: green;
}
```
@@ -18,7 +18,7 @@ You can change the background color using the following CSS:
You can change the line number foreground color using the following CSS:
```css
.editor.is-focused .line-number.cursor-line {
.editor .line-number.cursor-line {
color: blue;
}
```

View File

@@ -80,6 +80,9 @@ bool AtomCefClient::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
else if (name == "show") {
Show(browser);
}
else if (name == "toggleFullScreen") {
ToggleFullScreen(browser);
}
else {
return false;
}

View File

@@ -124,6 +124,7 @@ class AtomCefClient : public CefClient,
void Exit(int status);
void Log(const char *message);
void Show(CefRefPtr<CefBrowser> browser);
void ToggleFullScreen(CefRefPtr<CefBrowser> browser);
IMPLEMENT_REFCOUNTING(AtomCefClient);
IMPLEMENT_LOCKING(AtomCefClient);

View File

@@ -118,6 +118,10 @@ void AtomCefClient::Show(CefRefPtr<CefBrowser> browser) {
[windowController.webView setHidden:NO];
}
void AtomCefClient::ToggleFullScreen(CefRefPtr<CefBrowser> browser) {
[[browser->GetHost()->GetWindowHandle() window] toggleFullScreen:nil];
}
void AtomCefClient::ShowSaveDialog(int replyId, CefRefPtr<CefBrowser> browser) {
CefRefPtr<CefProcessMessage> replyMessage = CefProcessMessage::Create("reply");
CefRefPtr<CefListValue> replyArguments = replyMessage->GetArgumentList();

View File

@@ -69,6 +69,7 @@
[self initWithBootstrapScript:@"window-bootstrap" background:YES alwaysUseBundleResourcePath:stable];
[self.window setFrame:NSMakeRect(0, 0, 0, 0) display:NO];
[self.window setExcludedFromWindowsMenu:YES];
[self.window setCollectionBehavior:NSWindowCollectionBehaviorStationary];
return self;
}

View File

@@ -1159,3 +1159,17 @@ describe 'Buffer', ->
buffer.setText("\ninitialtext")
buffer.append("hello\n1\r\n2\n")
expect(buffer.getText()).toBe "\ninitialtexthello\n1\n2\n"
describe ".clipPosition(position)", ->
describe "when the position is before the start of the buffer", ->
it "returns the first position in the buffer", ->
expect(buffer.clipPosition([-1,0])).toEqual [0,0]
expect(buffer.clipPosition([0,-1])).toEqual [0,0]
expect(buffer.clipPosition([-1,-1])).toEqual [0,0]
describe "when the position is after the end of the buffer", ->
it "returns the last position in the buffer", ->
buffer.setText('some text')
expect(buffer.clipPosition([1, 0])).toEqual [0,9]
expect(buffer.clipPosition([0,10])).toEqual [0,9]
expect(buffer.clipPosition([10,Infinity])).toEqual [0,9]

View File

@@ -111,11 +111,9 @@ describe "Editor", ->
editor.isFocused = false
editor.hiddenInput.focus()
expect(editor.isFocused).toBeTruthy()
expect(editor).toHaveClass('is-focused')
editor.hiddenInput.focusout()
expect(editor.isFocused).toBeFalsy()
expect(editor).not.toHaveClass('is-focused')
describe "when the activeEditSession's file is modified on disk", ->
it "triggers an alert", ->
@@ -2544,3 +2542,46 @@ describe "Editor", ->
editor.trigger 'editor:move-line-down'
expect(buffer.lineForRow(1)).toBe ' if (items.length <= 1) return items;'
expect(buffer.lineForRow(2)).toBe ' var sort = function(items) {'
describe "when editor:duplicate-line is triggered", ->
describe "where there is no selection", ->
describe "when the cursor isn't on a folded line", ->
it "duplicates the current line below and moves the cursor down one row", ->
editor.setCursorBufferPosition([0, 5])
editor.trigger 'editor:duplicate-line'
expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {'
expect(buffer.lineForRow(1)).toBe 'var quicksort = function () {'
expect(editor.getCursorBufferPosition()).toEqual [1, 5]
describe "when the cursor is on a folded line", ->
it "duplicates the entire fold before and moves the cursor to the new fold", ->
editor.setCursorBufferPosition([4])
editor.foldCurrentRow()
editor.trigger 'editor:duplicate-line'
expect(editor.getCursorScreenPosition()).toEqual [5]
expect(editor.isFoldedAtScreenRow(4)).toBeTruthy()
expect(editor.isFoldedAtScreenRow(5)).toBeTruthy()
expect(buffer.lineForRow(8)).toBe ' while(items.length > 0) {'
expect(buffer.lineForRow(9)).toBe ' current = items.shift();'
expect(buffer.lineForRow(10)).toBe ' current < pivot ? left.push(current) : right.push(current);'
expect(buffer.lineForRow(11)).toBe ' }'
describe "when the cursor is on the last line and it doesn't have a trailing newline", ->
it "inserts a newline and the duplicated line", ->
editor.moveCursorToBottom()
editor.trigger 'editor:duplicate-line'
expect(buffer.lineForRow(12)).toBe '};'
expect(buffer.lineForRow(13)).toBe '};'
expect(buffer.lineForRow(14)).toBeUndefined()
expect(editor.getCursorBufferPosition()).toEqual [13, 2]
describe "when the cursor in on the last line and it is only a newline", ->
it "duplicates the current line below and moves the cursor down one row", ->
editor.moveCursorToBottom()
editor.insertNewline()
editor.moveCursorToBottom()
editor.trigger 'editor:duplicate-line'
expect(buffer.lineForRow(13)).toBe ''
expect(buffer.lineForRow(14)).toBe ''
expect(buffer.lineForRow(15)).toBeUndefined()
expect(editor.getCursorBufferPosition()).toEqual [14, 0]

View File

@@ -5,6 +5,7 @@ describe "Window", ->
[rootView] = []
beforeEach ->
window.setUpEventHandlers()
window.attachRootView(require.resolve('fixtures'))
rootView = window.rootView
@@ -13,13 +14,24 @@ describe "Window", ->
atom.setRootViewStateForPath(rootView.project.getPath(), null)
$(window).off 'beforeunload'
describe "window is loaded", ->
it "has .is-focused on the body tag", ->
expect($("body").hasClass("is-focused")).toBe true
describe "when the window is loaded", ->
it "doesn't have .is-blurred on the body tag", ->
expect($("body")).not.toHaveClass("is-blurred")
it "doesn't have .is-focused on the window blur event", ->
$(window).blur()
expect($("body").hasClass("is-focused")).toBe false
describe "when the window is blurred", ->
beforeEach ->
$(window).trigger 'blur'
afterEach ->
$('body').removeClass('is-blurred')
it "adds the .is-blurred class on the body", ->
expect($("body")).toHaveClass("is-blurred")
describe "when the window is focused again", ->
it "removes the .is-blurred class from the body", ->
$(window).trigger 'focus'
expect($("body")).not.toHaveClass("is-blurred")
describe ".close()", ->
it "is triggered by the 'core:close' event", ->

View File

@@ -111,6 +111,9 @@ _.extend atom,
endTracing: ->
@sendMessageToBrowserProcess('endTracing')
toggleFullScreen: ->
@sendMessageToBrowserProcess('toggleFullScreen')
getRootViewStateForPath: (path) ->
if json = localStorage[path]
JSON.parse(json)

View File

@@ -218,13 +218,15 @@ class Buffer
range
clipPosition: (position) ->
{ row, column } = Point.fromObject(position)
row = 0 if row < 0
column = 0 if column < 0
row = Math.min(@getLastRow(), row)
column = Math.min(@lineLengthForRow(row), column)
new Point(row, column)
position = Point.fromObject(position)
eofPosition = @getEofPosition()
if position.isGreaterThan(eofPosition)
eofPosition
else
row = Math.max(position.row, 0)
column = Math.max(position.column, 0)
column = Math.min(@lineLengthForRow(row), column)
new Point(row, column)
clipRange: (range) ->
range = Range.fromObject(range)

View File

@@ -307,6 +307,9 @@ class EditSession
fold.destroy()
@setCursorBufferPosition([fold.startRow, 0])
isFoldedAtCursorRow: ->
@isFoldedAtScreenRow(@getCursorScreenRow())
isFoldedAtBufferRow: (bufferRow) ->
screenRow = @screenPositionForBufferPosition([bufferRow]).row
@isFoldedAtScreenRow(screenRow)
@@ -408,6 +411,28 @@ class EditSession
@setSelectedBufferRange(selection.translate([1]), preserveFolds: true)
duplicateLine: ->
return unless @getSelection().isEmpty()
@transact =>
cursorPosition = @getCursorBufferPosition()
cursorRowFolded = @isFoldedAtCursorRow()
if cursorRowFolded
screenRow = @screenPositionForBufferPosition(cursorPosition).row
bufferRange = @bufferRangeForScreenRange([[screenRow], [screenRow + 1]])
else
bufferRange = new Range([cursorPosition.row], [cursorPosition.row + 1])
insertPosition = new Point(bufferRange.end.row)
if insertPosition.row >= @buffer.getLastRow()
@unfoldCurrentRow() if cursorRowFolded
@buffer.append("\n#{@getTextInBufferRange(bufferRange)}")
@foldCurrentRow() if cursorRowFolded
else
@buffer.insert(insertPosition, @getTextInBufferRange(bufferRange))
@setCursorScreenPosition(@getCursorScreenPosition().translate([1]))
@foldCurrentRow() if cursorRowFolded
mutateSelectedText: (fn) ->
@transact => fn(selection) for selection in @getSelections()

View File

@@ -186,6 +186,7 @@ class Editor extends View
'editor:copy-path': @copyPathToPasteboard
'editor:move-line-up': @moveLineUp
'editor:move-line-down': @moveLineDown
'editor:duplicate-line': @duplicateLine
documentation = {}
for name, method of editorBindings
@@ -210,6 +211,7 @@ class Editor extends View
moveLineUp: -> @activeEditSession.moveLineUp()
moveLineDown: -> @activeEditSession.moveLineDown()
setCursorScreenPosition: (position, options) -> @activeEditSession.setCursorScreenPosition(position, options)
duplicateLine: -> @activeEditSession.duplicateLine()
getCursorScreenPosition: -> @activeEditSession.getCursorScreenPosition()
getCursorScreenRow: -> @activeEditSession.getCursorScreenRow()
setCursorBufferPosition: (position, options) -> @activeEditSession.setCursorBufferPosition(position, options)
@@ -277,6 +279,7 @@ class Editor extends View
destroyFoldsContainingBufferRow: (bufferRow) -> @activeEditSession.destroyFoldsContainingBufferRow(bufferRow)
isFoldedAtScreenRow: (screenRow) -> @activeEditSession.isFoldedAtScreenRow(screenRow)
isFoldedAtBufferRow: (bufferRow) -> @activeEditSession.isFoldedAtBufferRow(bufferRow)
isFoldedAtCursorRow: -> @activeEditSession.isFoldedAtCursorRow()
lineForScreenRow: (screenRow) -> @activeEditSession.lineForScreenRow(screenRow)
linesForScreenRows: (start, end) -> @activeEditSession.linesForScreenRows(start, end)
@@ -355,8 +358,8 @@ class Editor extends View
@hiddenInput.on 'focusout', =>
@isFocused = false
@removeClass 'is-focused'
@autosave() if config.get "editor.autosave"
@removeClass 'is-focused'
@underlayer.on 'click', (e) =>
return unless e.target is @underlayer[0]

View File

@@ -28,6 +28,7 @@
'meta--': 'window:decrease-font-size'
'ctrl-w w': 'window:focus-next-pane'
'ctrl-tab': 'window:focus-next-pane'
'ctrl-meta-f': 'window:toggle-full-screen'
'alt-meta-i': 'toggle-dev-tools'

View File

@@ -40,3 +40,4 @@
'ctrl-C': 'editor:copy-path'
'ctrl-meta-up': 'editor:move-line-up'
'ctrl-meta-down': 'editor:move-line-down'
'meta-D': 'editor:duplicate-line'

View File

@@ -25,11 +25,14 @@ windowAdditions =
@syntax = new Syntax
@setUpKeymap()
@pasteboard = new Pasteboard
@setUpEventHandlers()
setUpEventHandlers: ->
$(window).on 'core:close', => @close()
$(window).command 'window:close', => @close()
$(window).on 'focus', => $("body").addClass("is-focused")
$(window).on 'blur', => $("body").removeClass("is-focused")
$(window).command 'window:toggle-full-screen', => atom.toggleFullScreen()
$(window).on 'focus', -> $("body").removeClass('is-blurred')
$(window).on 'blur', -> $("body").addClass('is-blurred')
# This method is intended only to be run when starting a normal application
# Note: RootView assigns itself on window on initialization so that
@@ -51,8 +54,8 @@ windowAdditions =
atom.setWindowState('pathToOpen', @rootView.project.getPath())
@rootView.deactivate()
@rootView = null
$(window).unbind('focus')
$(window).unbind('blur')
$(window).off('focus')
$(window).off('blur')
$(window).off('before')
setUpKeymap: ->

View File

@@ -0,0 +1,120 @@
AtomPackage = require 'atom-package'
_ = require 'underscore'
{$$} = require 'space-pen'
Range = require 'range'
module.exports =
class BracketMatcher extends AtomPackage
startPairMatches:
'(': ')'
'[': ']'
'{': '}'
endPairMatches:
')': '('
']': '['
'}': '{'
pairHighlighted: false
activate: (rootView) ->
rootView.eachEditor (editor) => @subscribeToEditor(editor) if editor.attached
subscribeToEditor: (editor) ->
editor.on 'cursor:moved.bracket-matcher', => @updateMatch(editor)
editor.command 'editor:go-to-matching-bracket.bracket-matcher', =>
@goToMatchingPair(editor)
editor.on 'editor:will-be-removed', => editor.off('.bracket-matcher')
goToMatchingPair: (editor) ->
return unless @pairHighlighted
return unless underlayer = editor.pane()?.find('.underlayer')
position = editor.getCursorBufferPosition()
previousPosition = position.translate([0, -1])
startPosition = underlayer.find('.bracket-matcher:first').data('bufferPosition')
endPosition = underlayer.find('.bracket-matcher:last').data('bufferPosition')
if position.isEqual(startPosition)
editor.setCursorBufferPosition(endPosition.translate([0, 1]))
else if previousPosition.isEqual(startPosition)
editor.setCursorBufferPosition(endPosition)
else if position.isEqual(endPosition)
editor.setCursorBufferPosition(startPosition.translate([0, 1]))
else if previousPosition.isEqual(endPosition)
editor.setCursorBufferPosition(startPosition)
createView: (editor, bufferPosition) ->
pixelPosition = editor.pixelPositionForBufferPosition(bufferPosition)
view = $$ -> @div class: 'bracket-matcher'
view.data('bufferPosition', bufferPosition)
view.css('top', pixelPosition.top).css('left', pixelPosition.left)
view.width(editor.charWidth).height(editor.charHeight)
findCurrentPair: (editor, buffer, matches) ->
position = editor.getCursorBufferPosition()
currentPair = buffer.getTextInRange(Range.fromPointWithDelta(position, 0, 1))
unless matches[currentPair]
position = position.translate([0, -1])
currentPair = buffer.getTextInRange(Range.fromPointWithDelta(position, 0, 1))
matchingPair = matches[currentPair]
if matchingPair
{position, currentPair, matchingPair}
else
{}
findMatchingEndPair: (buffer, startPairPosition, startPair, endPair) ->
scanRange = new Range(startPairPosition.translate([0, 1]), buffer.getEofPosition())
regex = new RegExp("[#{_.escapeRegExp(startPair + endPair)}]", 'g')
endPairPosition = null
unpairedCount = 0
buffer.scanInRange regex, scanRange, (match, range, {stop}) =>
if match[0] is startPair
unpairedCount++
else if match[0] is endPair
unpairedCount--
endPairPosition = range.start
stop() if unpairedCount < 0
endPairPosition
findMatchingStartPair: (buffer, endPairPosition, startPair, endPair) ->
scanRange = new Range([0, 0], endPairPosition)
regex = new RegExp("[#{_.escapeRegExp(startPair + endPair)}]", 'g')
startPairPosition = null
unpairedCount = 0
scanner = (match, range, {stop}) =>
if match[0] is endPair
unpairedCount++
else if match[0] is startPair
unpairedCount--
startPairPosition = range.start
stop() if unpairedCount < 0
buffer.scanInRange(regex, scanRange, scanner, true)
startPairPosition
updateMatch: (editor) ->
return unless underlayer = editor.pane()?.find('.underlayer')
underlayer.find('.bracket-matcher').remove() if @pairHighlighted
@pairHighlighted = false
return unless editor.getSelection().isEmpty()
return if editor.isFoldedAtCursorRow()
buffer = editor.getBuffer()
{position, currentPair, matchingPair} = @findCurrentPair(editor, buffer, @startPairMatches)
if position
matchPosition = @findMatchingEndPair(buffer, position, currentPair, matchingPair)
else
{position, currentPair, matchingPair} = @findCurrentPair(editor, buffer, @endPairMatches)
if position
matchPosition = @findMatchingStartPair(buffer, position, matchingPair, currentPair)
if position? and matchPosition?
if position.isLessThan(matchPosition)
underlayer.append(@createView(editor, position))
underlayer.append(@createView(editor, matchPosition))
else
underlayer.append(@createView(editor, matchPosition))
underlayer.append(@createView(editor, position))
@pairHighlighted = true

View File

@@ -0,0 +1,2 @@
'.editor':
'ctrl-j': 'editor:go-to-matching-bracket'

View File

@@ -0,0 +1,86 @@
RootView = require 'root-view'
describe "bracket matching", ->
[rootView, editor] = []
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
atom.loadPackage('bracket-matcher')
rootView.attachToDom()
editor = rootView.getActiveEditor()
afterEach ->
rootView.deactivate()
describe "when the cursor is before a starting pair", ->
it "highlights the starting pair and ending pair", ->
editor.moveCursorToEndOfLine()
editor.moveCursorLeft()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
describe "when the cursor is after a starting pair", ->
it "highlights the starting pair and ending pair", ->
editor.moveCursorToEndOfLine()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
describe "when the cursor is before an ending pair", ->
it "highlights the starting pair and ending pair", ->
editor.moveCursorToBottom()
editor.moveCursorLeft()
editor.moveCursorLeft()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
describe "when the cursor is after an ending pair", ->
it "highlights the starting pair and ending pair", ->
editor.moveCursorToBottom()
editor.moveCursorLeft()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
describe "when the cursor is moved off a pair", ->
it "removes the starting pair and ending pair highlights", ->
editor.moveCursorToEndOfLine()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
editor.moveCursorToBeginningOfLine()
expect(editor.underlayer.find('.bracket-matcher').length).toBe 0
describe "pair balancing", ->
describe "when a second starting pair preceeds the first ending pair", ->
it "advances to the second ending pair", ->
editor.setCursorBufferPosition([8,42])
expect(editor.underlayer.find('.bracket-matcher').length).toBe 2
expect(editor.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([8,42])
expect(editor.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([8,54])
describe "when editor:go-to-matching-bracket is triggered", ->
describe "when the cursor is before the starting pair", ->
it "moves the cursor to after the ending pair", ->
editor.moveCursorToEndOfLine()
editor.moveCursorLeft()
editor.trigger "editor:go-to-matching-bracket"
expect(editor.getCursorBufferPosition()).toEqual [12, 1]
describe "when the cursor is after the starting pair", ->
it "moves the cursor to before the ending pair", ->
editor.moveCursorToEndOfLine()
editor.trigger "editor:go-to-matching-bracket"
expect(editor.getCursorBufferPosition()).toEqual [12, 0]
describe "when the cursor is before the ending pair", ->
it "moves the cursor to after the starting pair", ->
editor.setCursorBufferPosition([12, 0])
editor.trigger "editor:go-to-matching-bracket"
expect(editor.getCursorBufferPosition()).toEqual [0, 29]
describe "when the cursor is after the ending pair", ->
it "moves the cursor to before the starting pair", ->
editor.setCursorBufferPosition([12, 1])
editor.trigger "editor:go-to-matching-bracket"
expect(editor.getCursorBufferPosition()).toEqual [0, 28]

View File

@@ -0,0 +1,3 @@
.bracket-matcher {
position: absolute;
}

View File

@@ -2,6 +2,7 @@ $ = require 'jquery'
{$$$} = require 'space-pen'
ScrollView = require 'scroll-view'
_ = require 'underscore'
fs = require 'fs'
module.exports =
class PreviewList extends ScrollView
@@ -34,7 +35,9 @@ class PreviewList extends ScrollView
operation.index = index for operation, index in operations
operationsByPath = _.groupBy(operations, (operation) -> operation.getPath())
for path, ops of operationsByPath
@li class: 'path', =>
classes = ['path']
classes.push('readme') if fs.isReadme(path)
@li class: classes.join(' '), =>
@span path
@span "(#{ops.length})", class: 'path-match-number'
for operation in ops

View File

@@ -39,7 +39,9 @@ class FuzzyFinderView extends SelectList
$$ ->
@li =>
ext = fs.extension(path)
if fs.isCompressedExtension(ext)
if fs.isReadme(path)
typeClass = 'readme-name'
else if fs.isCompressedExtension(ext)
typeClass = 'compressed-name'
else if fs.isImageExtension(ext)
typeClass = 'image-name'

View File

@@ -6,40 +6,13 @@ class TagGenerator
constructor: (@path, @callback) ->
parsePrefix: (section = "") ->
if section.indexOf('class:') is 0
section.substring(6)
else if section.indexOf('namespace:') is 0
section.substring(10)
else if section.indexOf('file:') is 0
section.substring(5)
else if section.indexOf('signature:') is 0
section.substring(10)
else if section.indexOf('struct:') is 0
section.substring(7)
else
section
parseTagLine: (line) ->
sections = line.split('\t')
return null if sections.length < 4
label = sections[0]
line = parseInt(sections[2]) - 1
if sections.length > 5
if prefix = @parsePrefix(sections[4])
label = "#{prefix}::#{label}"
if suffix = @parsePrefix(sections[5])
label = "#{label}#{suffix}"
if sections.length > 3
position: new Point(parseInt(sections[2]) - 1)
name: sections[0]
else
if suffix = @parsePrefix(sections[4])
label = "#{label}#{suffix}"
tag =
position: new Point(line, 0)
name: label
return tag
null
generate: ->
options =

View File

@@ -17,7 +17,9 @@ class FileView extends View
@subscribe $(window), 'focus', => @updateStatus()
extension = fs.extension(@getPath())
if fs.isCompressedExtension(extension)
if fs.isReadme(@getPath())
@fileName.addClass('readme-icon')
else if fs.isCompressedExtension(extension)
@fileName.addClass('compressed-icon')
else if fs.isImageExtension(extension)
@fileName.addClass('image-icon')

View File

@@ -180,6 +180,12 @@ module.exports =
'.ron'
], ext, true) >= 0
isReadme: (path) ->
extension = @extension(path)
base = @base(path, extension).toLowerCase()
base is 'readme' and (extension is '' or @isMarkdownExtension(extension))
readObject: (path) ->
contents = @read(path)
if @extension(path) is '.cson'

View File

@@ -32,6 +32,10 @@
top: 1px;
}
.command-panel .preview-list .path.readme:before {
content: "\f007";
}
.command-panel .preview-list .operation {
padding-top: 2px;
padding-bottom: 2px;

View File

@@ -76,6 +76,10 @@
opacity: 1;
}
.editor.is-blurred .line.cursor-line {
background: rgba(0, 0, 0, 0);
}
.editor .invisible {
opacity: 0.2;
}
@@ -138,11 +142,15 @@
border-left: 1px solid;
}
.editor:not(.is-focused) .cursor,
.editor .cursor,
.editor.is-focused .cursor.blink-off {
visibility: hidden;
}
.editor.is-focused .cursor {
visibility: visible;
}
.editor .hidden-input {
position: absolute;
z-index: -1;

View File

@@ -30,4 +30,8 @@
.fuzzy-finder .file.pdf-name:before {
content: "\f014";
}
}
.fuzzy-finder .file.readme-name:before {
content: "\f007";
}

View File

@@ -112,6 +112,11 @@
top: -2px;
}
.tree-view .file .readme-icon:before {
content: "\f007";
top: -2px;
}
.tree-view .directory > .header .disclosure-arrow:before {
content: "\f05a";
}

View File

@@ -3,15 +3,15 @@
color: #c5c8c6;
}
.editor.is-focused .cursor {
.editor .cursor {
border-color: #FFFFFF;
}
.editor.is-focused .selection .region {
.editor .selection .region {
background-color: #333333;
}
.editor.is-focused .line-number.cursor-line-no-selection, .editor.is-focused .line.cursor-line {
.editor .line-number.cursor-line-no-selection, .editor .line.cursor-line {
background-color: rgba(255, 255, 255, 0.14);
}

View File

@@ -0,0 +1,21 @@
.is-blurred .tree-view {
background-color: #2a2a2a;
}
.is-blurred .tabs {
opacity: 0.8;
border-bottom-color: #525252;
}
.is-blurred .tab {
background-image: -webkit-linear-gradient(#444, #555);
}
.is-blurred .tab.active {
border: 1px solid #525252
}
.is-blurred .tab.active:before {
box-shadow: 2px 2px 0 #525252;
border-color: #696969;
}

View File

@@ -0,0 +1,5 @@
.bracket-matcher {
border-bottom: 1px solid #f8de7e;
margin-top: -1px;
opacity: .7;
}

View File

@@ -29,6 +29,10 @@
font-family: Consolas, "Liberation Mono", Courier, monospace;
}
.markdown-body a {
color: #4183c4;
}
.markdown-body ol > li {
list-style-type: decimal;
}

View File

@@ -8,6 +8,8 @@
"status-bar.css",
"markdown-preview.css",
"command-panel.css",
"command-logger.css"
"command-logger.css",
"blurred.css",
"bracket-matcher.css"
]
}

View File

@@ -4,7 +4,7 @@
box-shadow: inset 0 -1px 0 #2e2e2e, 0 1px 0 #191919;
}
.is-focused .tab {
.tab {
background-image: -webkit-linear-gradient(#444, #3d3d3d);
border-top: 1px solid #383838;
border-right: 1px solid #2e2e2e;
@@ -12,38 +12,16 @@
box-shadow: inset 0 0 5px #383838, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a, inset 1px 0 0 #4a4a4a;
}
.is-focused .tab:first-child {
.tab:first-child {
box-shadow: inset 0 0 5px #383838, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a;
}
.is-focused .tab.active,
.is-focused .tab.active:hover {
border-top: 1px solid #4a4a4a;
box-shadow: inset -1px 0 0 #595959, inset 1px 0 0 #595959;
border-bottom-color: #424242;
background-image: -webkit-linear-gradient(#555555, #424242);
}
.tab {
background-color: #555;
background-image: none;
border-top: 1px solid #383838;
border-right: 1px solid #2e2e2e;
border-bottom: 1px solid #2e2e2e;
box-shadow: inset 0 0 5px #555, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a, inset 1px 0 0 #4a4a4a;
}
.tab:first-child {
box-shadow: inset 0 0 5px #555, 0 1px 0 #585858, inset -1px 0 0 #4a4a4a;
}
.tab.active,
.tab.active:hover {
border-top: 1px solid #4a4a4a;
box-shadow: inset -1px 0 0 #595959, inset 1px 0 0 #595959;
border-bottom-color: #424242;
background-image: none;
background-color: #424242;
background-image: -webkit-linear-gradient(#555555, #424242);
}
.tab,
@@ -55,9 +33,9 @@
border-color: #aaa;
}
.is-focused .tab.active,
.is-focused .tab.active:hover,
.is-focused .tab.active .close-icon {
.tab.active,
.tab.active:hover,
.tab.active .close-icon {
color: #e6e6e6;
}
@@ -74,8 +52,8 @@
border: 3px solid #777;
}
.is-focused .tab.active:first-child,
.is-focused .tab.active:first-child:hover {
.tab.active:first-child,
.tab.active:first-child:hover {
box-shadow: inset -1px 0 0 #595959;
}
@@ -84,18 +62,6 @@
border: 1px solid #595959;
}
.is-focused .tab.active:before {
border-bottom-right-radius: 4px;
border-width: 0 1px 1px 0;
box-shadow: 2px 2px 0 #424242;
}
.is-focused .tab.active:after {
border-bottom-left-radius: 4px;
border-width: 0 0 1px 1px;
box-shadow: -2px 2px 0 #424242;
}
.tab.active:before {
border-bottom-right-radius: 4px;
border-width: 0 1px 1px 0;
@@ -104,6 +70,7 @@
.tab.active:after {
border-bottom-left-radius: 4px;
border-width: 0 0 1px 1px;
box-shadow: -2px 2px 0 #424242;
}

View File

@@ -1,10 +1,5 @@
.is-focused .tree-view {
background: #1e1e1e;
border-right: 1px solid #191919;
}
.tree-view {
background: #2e2e2e;
background: #1e1e1e;
border-right: 1px solid #191919;
}
@@ -17,13 +12,8 @@
color: #d2d2d2;
}
.is-focused .tree-view .selected > .highlight {
background-image: -webkit-linear-gradient(#4e4e4e, #434343);
}
.tree-view .selected > .highlight {
background-image: none;
background-color: #6e6e6e;
background-image: -webkit-linear-gradient(#4e4e4e, #434343);
}
.tree-view:focus .selected > .highlight {

View File

@@ -0,0 +1,38 @@
.is-blurred .tab {
background-image: none;
background-color: #e0e0e0);
border-top: none;
border-right: 1px solid #959595;
border-bottom: 1px solid #959595;
box-shadow: inset 0 0 5px #eee, 0 1px 0 #eee, inset -1px 0 0 #e0e0e0, inset 1px 0 0 #e0e0e0;
color: #323232;
}
.is-blurred .tab.active {
border-bottom: 1px solid #e5e5e5;
box-shadow: inset 0 0 5px #eee, inset -1px 0 0 #e0e0e0, inset 1px 0 0 #e0e0e0;
}
.is-blurred .tree-view {
background: #f3f3f3;
border-right: 1px solid #c5c5c5;
}
.is-blurred .tree-view:focus .selected > .highlight {
border-top: 1px solid #3D4552;
border-bottom: 1px solid #3D4552;
background-image: none;
background-color: #69717b;
}
.is-blurred .tree-view .selected > .highlight {
box-sizing: border-box;
border-top: 1px solid #97a4a7;
border-bottom: 1px solid #97a4a7;
background-image: none;
background-color: #DFDFDF;
}
.is-blurred .tree-view .name:before {
color: #7e7e7e;
}

View File

@@ -0,0 +1,5 @@
.bracket-matcher {
border-bottom: 1px solid #f8de7e;
margin-top: -1px;
opacity: .7;
}

View File

@@ -29,6 +29,10 @@
font-family: Consolas, "Liberation Mono", Courier, monospace;
}
.markdown-body a {
color: #4183c4;
}
.markdown-body ol > li {
list-style-type: decimal;
}

View File

@@ -8,6 +8,8 @@
"status-bar.css",
"markdown-preview.css",
"command-panel.css",
"command-logger.css"
"command-logger.css",
"blurred.css",
"bracket-matcher.css"
]
}

View File

@@ -4,18 +4,8 @@
box-shadow: inset 0 -1px 0 #959595, 0 1px 0 #989898;
}
.is-focused .tab {
background-image: -webkit-linear-gradient(#e0e0e0, #bfbfbf);
border-top: none;
border-right: 1px solid #959595;
border-bottom: 1px solid #959595;
box-shadow: inset 0 0 5px #eee, 0 1px 0 #eee, inset -1px 0 0 #e0e0e0, inset 1px 0 0 #e0e0e0;
color: #323232;
}
.tab {
background-image: none;
background-color: #e0e0e0);
background-image: -webkit-linear-gradient(#e0e0e0, #bfbfbf);
border-top: none;
border-right: 1px solid #959595;
border-bottom: 1px solid #959595;

View File

@@ -1,13 +1,8 @@
.is-focused .tree-view {
.tree-view {
background: #dde3e8;
border-right: 1px solid #989898;
}
.tree-view {
background: #f3f3f3;
border-right: 1px solid #c5c5c5;
}
.tree-view .entry {
text-shadow: 0 1px 0 #fff;
}
@@ -17,7 +12,7 @@
color: #262626;
}
.is-focused .tree-view .selected > .highlight {
.tree-view .selected > .highlight {
box-sizing: border-box;
border-top: 1px solid #97a4a7;
border-bottom: 1px solid #97a4a7;
@@ -25,25 +20,10 @@
background-image: -webkit-linear-gradient(#cad5d8, #bcccce);
}
.tree-view .selected > .highlight {
box-sizing: border-box;
border-top: 1px solid #97a4a7;
border-bottom: 1px solid #97a4a7;
background-image: none;
background-color: #DFDFDF;
}
.is-focused .tree-view:focus .selected > .highlight {
border-top: 1px solid #3D4552;
border-bottom: 1px solid #3D4552;
background-image: -webkit-linear-gradient(#7e868d, #69717b);
}
.tree-view:focus .selected > .highlight {
border-top: 1px solid #3D4552;
border-bottom: 1px solid #3D4552;
background-image: none;
background-color: #69717b;
background-image: -webkit-linear-gradient(#7e868d, #69717b);
}
.tree-view:focus .directory.selected > .header > .name,
@@ -62,13 +42,10 @@
color: #262626;
}
.is-focused .tree-view .name:before {
.tree-view .name:before {
color: #7e8692;
}
.tree-view .name:before {
color: #7e7e7e;
}
.tree-view .entry:hover,
.tree-view .directory .header:hover .name,