mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-20 15:37:46 +03:00
Merge remote-tracking branch 'origin/master' into making-things-easy
This commit is contained in:
commit
1168404d6d
24
bundles/less.tmbundle/Commands/Save to CSS.tmCommand
Executable file
24
bundles/less.tmbundle/Commands/Save to CSS.tmCommand
Executable 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
47
bundles/less.tmbundle/README.md
Executable 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
|
344
bundles/less.tmbundle/Syntaxes/LESS.tmLanguage
Executable file
344
bundles/less.tmbundle/Syntaxes/LESS.tmLanguage
Executable 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>(?<!\*)\*\*/|^\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>(?<=[\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:]]]*)|((?>(['"])(?:[^\\]|\\.)*?(\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>\$|%|&|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\|\||\?\:|\*=|(?<!\()/=|%=|\+=|\-=|&=|\^=|\/\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>
|
15
bundles/less.tmbundle/info.plist
Executable file
15
bundles/less.tmbundle/info.plist
Executable 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>
|
44
bundles/less.tmbundle/sample.less
Executable file
44
bundles/less.tmbundle/sample.less
Executable 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
BIN
bundles/less.tmbundle/sample.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
@ -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)
|
||||
|
@ -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)
|
||||
|
36
spec/extensions/wrap-guide-spec.coffee
Normal file
36
spec/extensions/wrap-guide-spec.coffee
Normal 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)
|
@ -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)
|
||||
|
@ -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: ->
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -5,3 +5,5 @@ window.keymap.bindKeys '*'
|
||||
left: 'move-left'
|
||||
down: 'move-down'
|
||||
up: 'move-up'
|
||||
pagedown: 'page-down'
|
||||
pageup: 'page-up'
|
||||
|
@ -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'
|
||||
|
@ -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]
|
||||
|
1
src/extensions/wrap-guide/index.coffee
Normal file
1
src/extensions/wrap-guide/index.coffee
Normal file
@ -0,0 +1 @@
|
||||
module.exports = require 'wrap-guide/wrap-guide'
|
30
src/extensions/wrap-guide/wrap-guide.coffee
Normal file
30
src/extensions/wrap-guide/wrap-guide.coffee
Normal 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
8
static/wrap-guide.css
Normal file
@ -0,0 +1,8 @@
|
||||
.wrap-guide {
|
||||
height: 100%;
|
||||
width: 1px;
|
||||
background: rgba(150, 150, 150, .33);
|
||||
z-index: 100;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
}
|
Loading…
Reference in New Issue
Block a user