Merge remote-tracking branch 'origin/master' into making-things-easy

This commit is contained in:
Corey Johnson 2012-09-19 16:12:46 -07:00
commit 1168404d6d
19 changed files with 681 additions and 14 deletions

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>beforeRunningCommand</key>
<string>saveActiveFile</string>
<key>command</key>
<string>#!/usr/bin/env ruby
file = STDIN.read[/lessc: ([^*]+\.less)/, 1] || ENV["TM_FILEPATH"]
system("lessc --verbose \"#{file}\"")</string>
<key>input</key>
<string>document</string>
<key>keyEquivalent</key>
<string>@s</string>
<key>name</key>
<string>Save to CSS</string>
<key>output</key>
<string>showAsTooltip</string>
<key>scope</key>
<string>source.css.less</string>
<key>uuid</key>
<string>78788223-5E5E-434E-98BE-17BCDF600611</string>
</dict>
</plist>

47
bundles/less.tmbundle/README.md Executable file
View File

@ -0,0 +1,47 @@
# LESS TextMate bundle
Syntax highlighting for `.less` files. To learn more about [LESS][], see <http://lesscss.org/docs.html>.
This bundle was forked from `appden/less.tmbundle` but has since been rewritten from scratch (the language syntax).
[`sample.less`](http://github.com/rsms/less.tmbundle/blob/master/sample.less):
<img src="http://github.com/rsms/less.tmbundle/raw/master/sample.png" width="600" height="465" />
<small>Rendered in the ["Hunch Dark dimmed" theme](http://github.com/rsms/workenv/blob/master/textmate/Hunch-Dark-dimmed.tmTheme)</small>
## Compiling to CSS (⌘B)
Runs `lessc` on the current file, saving to the same file name with a .css extension (e.g. style.less => style.css). When there is `lessc: somefile.less` somewhere in the current file, that file is compiled instead.
Compiling requires some version of `lessc` to be in your `PATH`.
## Authors
* Rasmus Andersson <http://hunch.se/> rsms@github
* Scott Kyle <http://appden.com/> appden@github
## License (MIT)
Copyright (c) 2010 Scott Kyle and Rasmus Andersson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
[LESS]: http://lesscss.org

View File

@ -0,0 +1,344 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>comment</key>
<string>LeSS</string>
<key>fileTypes</key>
<array>
<string>less</string>
</array>
<key>foldingStartMarker</key>
<string>/\*\*(?!\*)|\{\s*($|/\*(?!.*?\*/.*\S))</string>
<key>foldingStopMarker</key>
<string>(?&lt;!\*)\*\*/|^\s*\}</string>
<key>keyEquivalent</key>
<string>^~L</string>
<key>name</key>
<string>LESS</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\b(a|abbr|acronym|address|area|b|base|big|blockquote|body|br|button|caption|cite|code|col|colgroup|dd|del|dfn|div|dl|dt|em|fieldset|figure|form|frame|frameset|(h[1-6])|head|hr|html|i|iframe|img|input|ins|kbd|label|legend|li|link|map|meta|noframes|noscript|object|ol|optgroup|option|p|param|pre|q|samp|script|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|title|tr|tt|ul|var|header|section|footer|article|nav|aside|hgroup|time|mark)\b</string>
<key>name</key>
<string>keyword.control.html.elements</string>
</dict>
<dict>
<key>begin</key>
<string>"</string>
<key>end</key>
<string>"</string>
<key>name</key>
<string>string.quoted.double.css</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\.</string>
<key>name</key>
<string>constant.character.escaped.css</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>'</string>
<key>end</key>
<string>'</string>
<key>name</key>
<string>string.quoted.single.css</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\.</string>
<key>name</key>
<string>constant.character.escaped.css</string>
</dict>
</array>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>entity.other.attribute-name.class.css</string>
</dict>
</dict>
<key>match</key>
<string>(\.[a-zA-Z0-9_-]+)[\s,{;]</string>
</dict>
<dict>
<key>begin</key>
<string>url\(</string>
<key>contentName</key>
<string>variable.parameter.url</string>
<key>end</key>
<string>\)</string>
<key>name</key>
<string>support.function.any-method.builtin.css</string>
</dict>
<dict>
<key>match</key>
<string>(#)([0-9a-fA-F]{3}|[0-9a-fA-F]{6})\b</string>
<key>name</key>
<string>constant.other.rgb-value.css</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>entity.other.attribute-name.id</string>
</dict>
</dict>
<key>match</key>
<string>#[a-zA-Z0-9_-]+</string>
<key>name</key>
<string>meta.selector.css</string>
</dict>
<dict>
<key>begin</key>
<string>/\*</string>
<key>end</key>
<string>\*/</string>
<key>name</key>
<string>comment.block.css</string>
</dict>
<dict>
<key>match</key>
<string>(-|\+)?\s*[0-9]+(\.[0-9]+)?</string>
<key>name</key>
<string>constant.numeric.css</string>
</dict>
<dict>
<key>match</key>
<string>(?&lt;=[\d])(px|pt|cm|mm|in|em|ex|pc)\b|%</string>
<key>name</key>
<string>keyword.unit.css</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.entity.css</string>
</dict>
</dict>
<key>match</key>
<string>(:+)\b(after|before|first-child|first-letter|first-line|selection)\b</string>
<key>name</key>
<string>entity.other.attribute-name.pseudo-element.css</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.entity.css</string>
</dict>
</dict>
<key>match</key>
<string>(:)\b(active|hover|link|visited|focus)\b</string>
<key>name</key>
<string>entity.other.attribute-name.pseudo-class.css</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>punctuation.definition.entity.css</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>entity.other.attribute-name.attribute.css</string>
</dict>
<key>3</key>
<dict>
<key>name</key>
<string>punctuation.separator.operator.css</string>
</dict>
<key>4</key>
<dict>
<key>name</key>
<string>string.unquoted.attribute-value.css</string>
</dict>
<key>5</key>
<dict>
<key>name</key>
<string>string.quoted.double.attribute-value.css</string>
</dict>
<key>6</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.begin.css</string>
</dict>
<key>7</key>
<dict>
<key>name</key>
<string>punctuation.definition.string.end.css</string>
</dict>
</dict>
<key>match</key>
<string>(?i)(\[)\s*(-?[_a-z\\[[:^ascii:]]][_a-z0-9\-\\[[:^ascii:]]]*)(?:\s*([~|^$*]?=)\s*(?:(-?[_a-z\\[[:^ascii:]]][_a-z0-9\-\\[[:^ascii:]]]*)|((?&gt;(['"])(?:[^\\]|\\.)*?(\6)))))?\s*(\])</string>
<key>name</key>
<string>meta.attribute-selector.css</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>keyword.control.at-rule.import.css</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>punctuation.definition.keyword.css</string>
</dict>
</dict>
<key>match</key>
<string>^\s*((@)import\b)</string>
<key>name</key>
<string>meta.at-rule.import.css</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>support.type.property-name.css.vendor</string>
</dict>
</dict>
<key>match</key>
<string>(-(?:webkit|moz|khtml|o|icab)-(?:background-size|border-radius|box-shadow|opacity|border-image))\s*:</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>support.type.property-name.css</string>
</dict>
</dict>
<key>match</key>
<string>\b(azimuth|background-attachment|background-color|background-clip|background-image|background-position|background-repeat|background-size|background|behavior|border-bottom-color|border-bottom-style|border-bottom-width|border-bottom|border-collapse|border-color|border-left-color|border-left-style|border-left-width|border-left|border-right-color|border-right-style|border-right-width|border-right|border-spacing|border-style|border-top-color|border-top-style|border-top-width|border-top|border-width|border-radius|border|box-shadow|bottom|caption-side|clear|clip|color|content|counter-increment|counter-reset|cue-after|cue-before|cue|cursor|direction|display|elevation|empty-cells|float|font-family|font-size-adjust|font-size|font-stretch|font-style|font-variant|font-weight|font|height|left|letter-spacing|line-height|list-style-image|list-style-position|list-style-type|list-style|margin-bottom|margin-left|margin-right|margin-top|marker-offset|margin|marks|max-height|max-width|min-height|min-width|opacity|orphans|outline-color|outline-style|outline-width|outline|overflow(-[xy])?|padding-bottom|padding-left|padding-right|padding-top|padding|page-break-after|page-break-before|page-break-inside|page|pause-after|pause-before|pause|pitch-range|pitch|play-during|position|quotes|richness|right|size|speak-header|speak-numeral|speak-punctuation|speech-rate|speak|stress|table-layout|text-align|text-decoration|text-indent|text-shadow|text-transform|top|unicode-bidi|vertical-align|visibility|voice-family|volume|white-space|widows|width|word-spacing|z-index)\s*:</string>
</dict>
<dict>
<key>match</key>
<string>\b(absolute|all-scroll|always|auto|baseline|below|bidi-override|block|bold|bolder|both|bottom|break-all|break-word|capitalize|center|char|circle|col-resize|collapse|crosshair|dashed|decimal|default|disabled|disc|distribute-all-lines|distribute-letter|distribute-space|distribute|dotted|double|e-resize|ellipsis|fixed|groove|hand|help|hidden|horizontal|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|inactive|inherit|inline-block|inline|inset|inside|inter-ideograph|inter-word|italic|justify|keep-all|left|lighter|line-edge|line-through|line|linear|list-item|loose|lower-alpha|lower-roman|lowercase|lr-tb|ltr|medium|middle|move|n-resize|ne-resize|newspaper|no-drop|no-repeat|nw-resize|none|normal|not-allowed|nowrap|oblique|outset|outside|overline|pointer|progress|relative|repeat-x|repeat-y|repeat|right|ridge|row-resize|rtl|s-resize|scroll|se-resize|separate|small-caps|solid|square|static|strict|super|sw-resize|table-footer-group|table-header-group|tb-rl|text-bottom|text-top|text|thick|thin|top|transparent|underline|upper-alpha|upper-roman|uppercase|vertical-ideographic|vertical-text|visible|w-resize|wait|whitespace|padding-box)\b</string>
<key>name</key>
<string>support.constant.property-value.css</string>
</dict>
<dict>
<key>match</key>
<string>(\b(?i:arial|century|comic|courier|garamond|georgia|helvetica|impact|lucida|symbol|system|tahoma|times|trebuchet|utopia|verdana|webdings|sans-serif|serif|monospace)\b)</string>
<key>name</key>
<string>support.constant.font-name.css</string>
</dict>
<dict>
<key>comment</key>
<string>http://www.w3.org/TR/CSS21/syndata.html#value-def-color</string>
<key>match</key>
<string>\b(aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow)\b</string>
<key>name</key>
<string>support.constant.color.w3c-standard-color-name.css</string>
</dict>
<dict>
<key>match</key>
<string>\b(saturate|desaturate|lighten|darken|grayscale)\b</string>
<key>name</key>
<string>support.function.any-method.builtin.less</string>
</dict>
<dict>
<key>match</key>
<string>\b(rgb|rgba|hsl|hsla|url)\b</string>
<key>name</key>
<string>support.function.any-method.builtin.css</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>support.function.any-method.vendor.css</string>
</dict>
</dict>
<key>match</key>
<string>(-(?:webkit|moz|khtml|o|icab)-(?:gradient|linear-gradient))</string>
</dict>
<dict>
<key>match</key>
<string>\b(color-stop|from|to)\b</string>
<key>name</key>
<string>support.function.any-method.webkit.gradient.css</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>support.function.less</string>
</dict>
</dict>
<key>match</key>
<string>(\.[a-zA-Z0-9_-]+)\s*(;|\()</string>
</dict>
<dict>
<key>begin</key>
<string>//</string>
<key>end</key>
<string>$\n?</string>
<key>name</key>
<string>comment.line.double-slash.less</string>
</dict>
<dict>
<key>match</key>
<string>@[a-zA-Z0-9_-][\w-]*</string>
<key>name</key>
<string>variable.other.less</string>
</dict>
<dict>
<key>match</key>
<string>\$|%|&amp;|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|&lt;=|&gt;=|&lt;&lt;=|&gt;&gt;=|&gt;&gt;&gt;=|&lt;&gt;|&lt;|&gt;|!|&amp;&amp;|\|\||\?\:|\*=|(?&lt;!\()/=|%=|\+=|\-=|&amp;=|\^=|\/\b</string>
<key>name</key>
<string>keyword.operator.less</string>
</dict>
<dict>
<key>match</key>
<string>\{|\}</string>
<key>name</key>
<string>meta.brace.curly.js</string>
</dict>
<dict>
<key>match</key>
<string>\(|\)</string>
<key>name</key>
<string>meta.brace.round.js</string>
</dict>
<dict>
<key>match</key>
<string>\[|\]</string>
<key>name</key>
<string>meta.brace.square.js</string>
</dict>
</array>
<key>scopeName</key>
<string>source.css.less</string>
<key>uuid</key>
<string>9343D324-75A1-4733-A5C0-5D1D4B6182D0</string>
</dict>
</plist>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>name</key>
<string>LESS</string>
<key>uuid</key>
<string>D1D51EE5-E89F-4B14-8AE4-FC364E540B47</string>
<key>ordering</key>
<array>
<string>78788223-5E5E-434E-98BE-17BCDF600611</string>
<string>9343D324-75A1-4733-A5C0-5D1D4B6182D0</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,44 @@
// Importing
@import "_base.less"
// Variables
@nice-blue: #5B83AD;
@light-blue: @nice-blue + #111;
#header { color: @light-blue; }
// Mixins
.bordered(@color: #f04) {
border-top: dotted 1px @color;
border-bottom: solid 2px @color;
}
#menu a {
.bordered(#f00); color:#111;
}
// Nested
#header {
h1 { font-size: 12px; }
.logo {
width: 300px;
:hover { text-decoration: none }
}
}
// Operations
@base: 5%;
@filler: @base * 2;
@other: @base + @filler;
td {
background-color: @base-color + #111;
height: 100% / 2 + @filler;
}
/*
Accessors
*/
.comment {
width: #defaults[@width];
color: .article['color'];
}

BIN
bundles/less.tmbundle/sample.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -1461,3 +1461,42 @@ describe "EditSession", ->
expect(editSession.clipBufferPosition([-1, -1])).toEqual [0,0]
expect(editSession.clipBufferPosition([Infinity, Infinity])).toEqual [12,2]
expect(editSession.clipBufferPosition([8, 57])).toEqual [8, 56]
describe ".deleteLine()", ->
it "deletes the first line when the cursor is there", ->
editSession.getLastCursor().moveToTop()
line1 = buffer.lineForRow(1)
count = buffer.getLineCount()
expect(buffer.lineForRow(0)).not.toBe(line1)
editSession.deleteLine()
expect(buffer.lineForRow(0)).toBe(line1)
expect(buffer.getLineCount()).toBe(count - 1)
it "deletes the last line when the cursor is there", ->
count = buffer.getLineCount()
secondToLastLine = buffer.lineForRow(count - 2)
expect(buffer.lineForRow(count - 1)).not.toBe(secondToLastLine)
editSession.getLastCursor().moveToBottom()
editSession.deleteLine()
newCount = buffer.getLineCount()
expect(buffer.lineForRow(newCount - 1)).toBe(secondToLastLine)
expect(newCount).toBe(count - 1)
it "deletes whole lines when partial lines are selected", ->
editSession.setSelectedBufferRange([[0, 2], [1, 2]])
line2 = buffer.lineForRow(2)
count = buffer.getLineCount()
expect(buffer.lineForRow(0)).not.toBe(line2)
expect(buffer.lineForRow(1)).not.toBe(line2)
editSession.deleteLine()
expect(buffer.lineForRow(0)).toBe(line2)
expect(buffer.getLineCount()).toBe(count - 2)
it "only deletes first line if only newline is selected on second line", ->
editSession.setSelectedBufferRange([[0, 2], [1, 0]])
line1 = buffer.lineForRow(1)
count = buffer.getLineCount()
expect(buffer.lineForRow(0)).not.toBe(line1)
editSession.deleteLine()
expect(buffer.lineForRow(0)).toBe(line1)
expect(buffer.getLineCount()).toBe(count - 1)

View File

@ -1654,3 +1654,44 @@ describe "Editor", ->
editor.edit(project.buildEditSessionForPath())
paths = editor.getOpenBufferPaths().map (path) -> project.relativize(path)
expect(paths).toEqual = ['sample.js', 'sample.txt', 'two-hundred.txt']
describe "paging up and down", ->
beforeEach ->
editor.attachToDom()
it "moves to the last line when page down is repeated from the first line", ->
rows = editor.getLineCount() - 1
expect(rows).toBeGreaterThan(0)
row = editor.getCursor(0).getScreenPosition().row
expect(row).toBe(0)
while row < rows
editor.pageDown()
newRow = editor.getCursor(0).getScreenPosition().row
expect(newRow).toBeGreaterThan(row)
if (newRow <= row)
break
row = newRow
expect(row).toBe(rows)
expect(editor.getLastVisibleScreenRow()).toBe(rows)
it "moves to the first line when page up is repeated from the last line", ->
editor.moveCursorToBottom()
row = editor.getCursor().getScreenPosition().row
expect(row).toBeGreaterThan(0)
while row > 0
editor.pageUp()
newRow = editor.getCursor().getScreenPosition().row
expect(newRow).toBeLessThan(row)
if (newRow >= row)
break
row = newRow
expect(row).toBe(0)
expect(editor.getFirstVisibleScreenRow()).toBe(0)
it "resets to original position when down is followed by up", ->
expect(editor.getCursor().getScreenPosition().row).toBe(0)
editor.pageDown()
expect(editor.getCursor().getScreenPosition().row).toBeGreaterThan(0)
editor.pageUp()
expect(editor.getCursor().getScreenPosition().row).toBe(0)
expect(editor.getFirstVisibleScreenRow()).toBe(0)

View File

@ -0,0 +1,36 @@
$ = require 'jquery'
RootView = require 'root-view'
describe "WrapGuide", ->
[rootView, editor, wrapGuide] = []
beforeEach ->
rootView = new RootView(require.resolve('fixtures/sample.js'))
requireExtension('wrap-guide')
rootView.attachToDom()
editor = rootView.getActiveEditor()
wrapGuide = rootView.find('.wrap-guide').view()
afterEach ->
rootView.deactivate()
describe "@initialize", ->
it "appends a wrap guide to all existing and new editors", ->
expect(rootView.panes.find('.pane').length).toBe 1
expect(rootView.panes.find('.lines > .wrap-guide').length).toBe 1
editor.splitRight()
expect(rootView.find('.pane').length).toBe 2
expect(rootView.panes.find('.lines > .wrap-guide').length).toBe 2
describe "@updateGuide", ->
it "positions the guide at the configured column", ->
width = editor.charWidth * wrapGuide.column
expect(width).toBeGreaterThan(0)
expect(wrapGuide.position().left).toBe(width)
describe "font-size-change", ->
it "updates the wrap guide position", ->
initial = wrapGuide.position().left
expect(initial).toBeGreaterThan(0)
rootView.trigger('increase-font-size')
expect(wrapGuide.position().left).toBeGreaterThan(initial)

View File

@ -162,13 +162,19 @@ class Buffer
new Point(row, index)
deleteRow: (row) ->
range = null
if row == @getLastRow()
range = new Range([row - 1, @lineLengthForRow(row - 1)], [row, @lineLengthForRow(row)])
else
range = new Range([row, 0], [row + 1, 0])
@deleteRows(row, row)
@change(range, '')
deleteRows: (start, end) ->
startPoint = null
endPoint = null
if end == @getLastRow()
startPoint = [start - 1, @lineLengthForRow(start - 1)]
endPoint = [end, @lineLengthForRow(end)]
else
startPoint = [start, 0]
endPoint = [end + 1, 0]
@change(new Range(startPoint, endPoint), '')
insert: (point, text) ->
@change(new Range(point, point), text)

View File

@ -54,16 +54,16 @@ class Cursor
refreshScreenPosition: ->
@anchor.refreshScreenPosition()
moveUp: ->
moveUp: (rowCount = 1) ->
{ row, column } = @getScreenPosition()
column = @goalColumn if @goalColumn?
@setScreenPosition({row: row - 1, column: column})
@setScreenPosition({row: row - rowCount, column: column})
@goalColumn = column
moveDown: ->
moveDown: (rowCount = 1) ->
{ row, column } = @getScreenPosition()
column = @goalColumn if @goalColumn?
@setScreenPosition({row: row + 1, column: column})
@setScreenPosition({row: row + rowCount, column: column})
@goalColumn = column
moveLeft: ->

View File

@ -167,6 +167,9 @@ class EditSession
deleteToEndOfWord: ->
@mutateSelectedText (selection) -> selection.deleteToEndOfWord()
deleteLine: ->
@mutateSelectedText (selection) -> selection.deleteLine()
indentSelectedRows: ->
@mutateSelectedText (selection) -> selection.indentSelectedRows()
@ -427,11 +430,11 @@ class EditSession
getTextInBufferRange: (range) ->
@buffer.getTextInRange(range)
moveCursorUp: ->
@moveCursors (cursor) -> cursor.moveUp()
moveCursorUp: (lineCount) ->
@moveCursors (cursor) -> cursor.moveUp(lineCount)
moveCursorDown: ->
@moveCursors (cursor) -> cursor.moveDown()
moveCursorDown: (lineCount) ->
@moveCursors (cursor) -> cursor.moveDown(lineCount)
moveCursorLeft: ->
@moveCursors (cursor) -> cursor.moveLeft()

View File

@ -111,6 +111,7 @@ class Editor extends View
'backspace-to-beginning-of-word': @backspaceToBeginningOfWord
'delete': @delete
'delete-to-end-of-word': @deleteToEndOfWord
'delete-line': @deleteLine
'cut-to-end-of-line': @cutToEndOfLine
'cut': @cutSelection
'copy': @copySelection
@ -131,6 +132,8 @@ class Editor extends View
'select-to-end-of-word': @selectToEndOfWord
'select-to-beginning-of-word': @selectToBeginningOfWord
'select-all': @selectAll
'page-down': @pageDown
'page-up': @pageUp
if not @mini
_.extend editorBindings,
@ -207,6 +210,7 @@ class Editor extends View
backspaceToBeginningOfWord: -> @activeEditSession.backspaceToBeginningOfWord()
delete: -> @activeEditSession.delete()
deleteToEndOfWord: -> @activeEditSession.deleteToEndOfWord()
deleteLine: -> @activeEditSession.deleteLine()
cutToEndOfLine: -> @activeEditSession.cutToEndOfLine()
insertText: (text) -> @activeEditSession.insertText(text)
insertNewline: -> @activeEditSession.insertNewline()
@ -246,6 +250,17 @@ class Editor extends View
bufferRowsForScreenRows: (startRow, endRow) -> @activeEditSession.bufferRowsForScreenRows(startRow, endRow)
stateForScreenRow: (row) -> @activeEditSession.stateForScreenRow(row)
pageDown: ->
newScrollTop = @scrollTop() + @scrollView[0].clientHeight
@activeEditSession.moveCursorDown(@getPageRows())
@scrollTop(newScrollTop, adjustVerticalScrollbar: true)
pageUp: ->
newScrollTop = @scrollTop() - @scrollView[0].clientHeight
@activeEditSession.moveCursorUp(@getPageRows())
@scrollTop(newScrollTop, adjustVerticalScrollbar: true)
getPageRows: ->
Math.max(1, Math.ceil(@scrollView[0].clientHeight / @lineHeight))
setText: (text) -> @getBuffer().setText(text)
getText: -> @getBuffer().getText()
getPath: -> @getBuffer().getPath()

View File

@ -5,3 +5,5 @@ window.keymap.bindKeys '*'
left: 'move-left'
down: 'move-down'
up: 'move-up'
pagedown: 'page-down'
pageup: 'page-up'

View File

@ -11,6 +11,7 @@ window.keymap.bindKeys '.editor',
'backspace': 'backspace'
'shift-backspace': 'backspace'
'delete': 'delete'
'meta-d': 'delete-line'
'meta-x': 'cut'
'meta-c': 'copy'
'meta-v': 'paste'

View File

@ -181,6 +181,17 @@ class Selection
@editSession.buffer.delete(bufferRange) unless bufferRange.isEmpty()
@cursor?.setBufferPosition(bufferRange.start)
deleteLine: ->
if @isEmpty()
@editSession.buffer.deleteRow(@cursor.getBufferPosition().row)
else
bufferRange = @getBufferRange()
start = bufferRange.start.row
end = bufferRange.end.row
if end isnt @editSession.buffer.getLastRow() and bufferRange.end.column is 0
end--
@editSession.buffer.deleteRows(start, end)
indentSelectedRows: ->
range = @getBufferRange()
for row in [range.start.row..range.end.row]

View File

@ -0,0 +1 @@
module.exports = require 'wrap-guide/wrap-guide'

View File

@ -0,0 +1,30 @@
{View} = require 'space-pen'
module.exports =
class WrapGuide extends View
@activate: (rootView) ->
requireStylesheet 'wrap-guide.css'
for editor in rootView.getEditors()
@appendToEditorPane(rootView, editor) if rootView.parents('html').length
rootView.on 'editor-open', (e, editor) =>
@appendToEditorPane(rootView, editor)
@appendToEditorPane: (rootView, editor) ->
if lines = editor.pane()?.find('.lines')
lines.append(new WrapGuide(rootView, editor))
@content: ->
@div class: 'wrap-guide'
column: 80
initialize: (@rootView, @editor) =>
@updateGuide(@editor)
@editor.on 'editor-path-change', => @updateGuide(@editor)
@rootView.on 'font-size-change', => @updateGuide(@editor)
updateGuide: (editor) ->
width = editor.charWidth * @column
@css("left", width + "px")

8
static/wrap-guide.css Normal file
View File

@ -0,0 +1,8 @@
.wrap-guide {
height: 100%;
width: 1px;
background: rgba(150, 150, 150, .33);
z-index: 100;
position: absolute;
top: 0px;
}