├── .eslintrc ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── block-cursor.png ├── cursor-bordered-box.png ├── cursor-i-beam.png ├── cursor-pulse.gif ├── cursor-underline.png ├── lib └── block-cursor.js ├── package.json └── styles └── block-cursor.less /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", // https://github.com/babel/babel-eslint 3 | "env": { // http://eslint.org/docs/user-guide/configuring.html#specifying-environments 4 | "browser": true, // browser global variables 5 | "node": true // Node.js global variables and Node.js-specific rules 6 | }, 7 | "globals": { 8 | "atom": true 9 | }, 10 | "ecmaFeatures": { 11 | "arrowFunctions": true, 12 | "blockBindings": true, 13 | "classes": true, 14 | "defaultParams": true, 15 | "destructuring": true, 16 | "forOf": true, 17 | "generators": false, 18 | "modules": true, 19 | "objectLiteralComputedProperties": true, 20 | "objectLiteralDuplicateProperties": false, 21 | "objectLiteralShorthandMethods": true, 22 | "objectLiteralShorthandProperties": true, 23 | "spread": true, 24 | "superInFunctions": true, 25 | "templateStrings": true 26 | }, 27 | "rules": { 28 | /** 29 | * Strict mode 30 | */ 31 | // babel inserts "use strict"; for us 32 | "strict": [2, "never"], // http://eslint.org/docs/rules/strict 33 | 34 | /** 35 | * ES6 36 | */ 37 | "no-var": 0, // http://eslint.org/docs/rules/no-var 38 | "prefer-const": 0, // http://eslint.org/docs/rules/prefer-const 39 | 40 | /** 41 | * Variables 42 | */ 43 | "no-shadow": 2, // http://eslint.org/docs/rules/no-shadow 44 | "no-shadow-restricted-names": 2, // http://eslint.org/docs/rules/no-shadow-restricted-names 45 | "no-unused-vars": [2, { // http://eslint.org/docs/rules/no-unused-vars 46 | "vars": "local", 47 | "args": "after-used" 48 | }], 49 | "no-use-before-define": 0, // http://eslint.org/docs/rules/no-use-before-define 50 | 51 | /** 52 | * Expressions 53 | */ 54 | 55 | "no-unused-expressions": 0, 56 | 57 | /** 58 | * Possible errors 59 | */ 60 | "comma-dangle": [2, "always-multiline"], // http://eslint.org/docs/rules/comma-dangle 61 | "no-cond-assign": [2, "always"], // http://eslint.org/docs/rules/no-cond-assign 62 | "no-console": 1, // http://eslint.org/docs/rules/no-console 63 | "no-debugger": 1, // http://eslint.org/docs/rules/no-debugger 64 | "no-alert": 1, // http://eslint.org/docs/rules/no-alert 65 | "no-constant-condition": 1, // http://eslint.org/docs/rules/no-constant-condition 66 | "no-dupe-keys": 2, // http://eslint.org/docs/rules/no-dupe-keys 67 | "no-duplicate-case": 2, // http://eslint.org/docs/rules/no-duplicate-case 68 | "no-empty": 2, // http://eslint.org/docs/rules/no-empty 69 | "no-ex-assign": 2, // http://eslint.org/docs/rules/no-ex-assign 70 | "no-extra-boolean-cast": 0, // http://eslint.org/docs/rules/no-extra-boolean-cast 71 | "no-extra-semi": 2, // http://eslint.org/docs/rules/no-extra-semi 72 | "no-func-assign": 2, // http://eslint.org/docs/rules/no-func-assign 73 | "no-inner-declarations": 2, // http://eslint.org/docs/rules/no-inner-declarations 74 | "no-invalid-regexp": 2, // http://eslint.org/docs/rules/no-invalid-regexp 75 | "no-irregular-whitespace": 2, // http://eslint.org/docs/rules/no-irregular-whitespace 76 | "no-obj-calls": 2, // http://eslint.org/docs/rules/no-obj-calls 77 | "no-reserved-keys": 0, // http://eslint.org/docs/rules/no-reserved-keys 78 | "no-sparse-arrays": 2, // http://eslint.org/docs/rules/no-sparse-arrays 79 | "no-unreachable": 2, // http://eslint.org/docs/rules/no-unreachable 80 | "use-isnan": 2, // http://eslint.org/docs/rules/use-isnan 81 | "block-scoped-var": 0, // http://eslint.org/docs/rules/block-scoped-var 82 | 83 | /** 84 | * Best practices 85 | */ 86 | "consistent-return": 0, // http://eslint.org/docs/rules/consistent-return 87 | "curly": [0, "multi-line"], // http://eslint.org/docs/rules/curly 88 | "default-case": 2, // http://eslint.org/docs/rules/default-case 89 | "dot-notation": [2, { // http://eslint.org/docs/rules/dot-notation 90 | "allowKeywords": true 91 | }], 92 | "eqeqeq": 0, // http://eslint.org/docs/rules/eqeqeq 93 | "guard-for-in": 2, // http://eslint.org/docs/rules/guard-for-in 94 | "no-caller": 2, // http://eslint.org/docs/rules/no-caller 95 | "no-else-return": 2, // http://eslint.org/docs/rules/no-else-return 96 | "no-eq-null": 2, // http://eslint.org/docs/rules/no-eq-null 97 | "no-eval": 2, // http://eslint.org/docs/rules/no-eval 98 | "no-extend-native": 2, // http://eslint.org/docs/rules/no-extend-native 99 | "no-extra-bind": 2, // http://eslint.org/docs/rules/no-extra-bind 100 | "no-fallthrough": 2, // http://eslint.org/docs/rules/no-fallthrough 101 | "no-floating-decimal": 2, // http://eslint.org/docs/rules/no-floating-decimal 102 | "no-implied-eval": 2, // http://eslint.org/docs/rules/no-implied-eval 103 | "no-lone-blocks": 2, // http://eslint.org/docs/rules/no-lone-blocks 104 | "no-loop-func": 2, // http://eslint.org/docs/rules/no-loop-func 105 | "no-multi-str": 2, // http://eslint.org/docs/rules/no-multi-str 106 | "no-native-reassign": 2, // http://eslint.org/docs/rules/no-native-reassign 107 | "no-new": 2, // http://eslint.org/docs/rules/no-new 108 | "no-new-func": 2, // http://eslint.org/docs/rules/no-new-func 109 | "no-new-wrappers": 2, // http://eslint.org/docs/rules/no-new-wrappers 110 | "no-octal": 2, // http://eslint.org/docs/rules/no-octal 111 | "no-octal-escape": 2, // http://eslint.org/docs/rules/no-octal-escape 112 | "no-param-reassign": 0, // http://eslint.org/docs/rules/no-param-reassign 113 | "no-proto": 2, // http://eslint.org/docs/rules/no-proto 114 | "no-redeclare": 2, // http://eslint.org/docs/rules/no-redeclare 115 | "no-return-assign": 2, // http://eslint.org/docs/rules/no-return-assign 116 | "no-script-url": 2, // http://eslint.org/docs/rules/no-script-url 117 | "no-self-compare": 2, // http://eslint.org/docs/rules/no-self-compare 118 | "no-sequences": 2, // http://eslint.org/docs/rules/no-sequences 119 | "no-throw-literal": 2, // http://eslint.org/docs/rules/no-throw-literal 120 | "no-with": 2, // http://eslint.org/docs/rules/no-with 121 | "radix": 0, // http://eslint.org/docs/rules/radix 122 | "vars-on-top": 0, // http://eslint.org/docs/rules/vars-on-top 123 | "wrap-iife": [2, "any"], // http://eslint.org/docs/rules/wrap-iife 124 | "yoda": 2, // http://eslint.org/docs/rules/yoda 125 | 126 | /** 127 | * Style 128 | */ 129 | "indent": [2, 2], // http://eslint.org/docs/rules/indent 130 | "brace-style": [2, // http://eslint.org/docs/rules/brace-style 131 | "1tbs", { 132 | "allowSingleLine": true 133 | }], 134 | "quotes": [ 135 | 2, "single", "avoid-escape" // http://eslint.org/docs/rules/quotes 136 | ], 137 | "camelcase": [2, { // http://eslint.org/docs/rules/camelcase 138 | "properties": "never" 139 | }], 140 | "comma-spacing": [2, { // http://eslint.org/docs/rules/comma-spacing 141 | "before": false, 142 | "after": true 143 | }], 144 | "comma-style": [2, "last"], // http://eslint.org/docs/rules/comma-style 145 | "eol-last": 2, // http://eslint.org/docs/rules/eol-last 146 | "func-names": 1, // http://eslint.org/docs/rules/func-names 147 | "key-spacing": [2, { // http://eslint.org/docs/rules/key-spacing 148 | "beforeColon": false, 149 | "afterColon": true 150 | }], 151 | "new-cap": [2, { // http://eslint.org/docs/rules/new-cap 152 | "newIsCap": true 153 | }], 154 | "no-multiple-empty-lines": [2, { // http://eslint.org/docs/rules/no-multiple-empty-lines 155 | "max": 2 156 | }], 157 | "no-nested-ternary": 2, // http://eslint.org/docs/rules/no-nested-ternary 158 | "no-new-object": 2, // http://eslint.org/docs/rules/no-new-object 159 | "no-spaced-func": 2, // http://eslint.org/docs/rules/no-spaced-func 160 | "no-trailing-spaces": 2, // http://eslint.org/docs/rules/no-trailing-spaces 161 | "no-wrap-func": 2, // http://eslint.org/docs/rules/no-wrap-func 162 | "no-underscore-dangle": 0, // http://eslint.org/docs/rules/no-underscore-dangle 163 | "one-var": [2, "never"], // http://eslint.org/docs/rules/one-var 164 | "padded-blocks": [2, "never"], // http://eslint.org/docs/rules/padded-blocks 165 | "semi": [2, "always"], // http://eslint.org/docs/rules/semi 166 | "semi-spacing": [2, { // http://eslint.org/docs/rules/semi-spacing 167 | "before": false, 168 | "after": true 169 | }], 170 | "space-after-keywords": 0, // http://eslint.org/docs/rules/space-after-keywords 171 | "space-before-blocks": 2, // http://eslint.org/docs/rules/space-before-blocks 172 | "space-before-function-paren": [2, "never"], // http://eslint.org/docs/rules/space-before-function-paren 173 | "space-infix-ops": 2, // http://eslint.org/docs/rules/space-infix-ops 174 | "space-return-throw-case": 2, // http://eslint.org/docs/rules/space-return-throw-case 175 | "spaced-line-comment": 2, // http://eslint.org/docs/rules/spaced-line-comment 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # block-cursor changelog 2 | 3 | ## 0.13.3 4 | 5 | * Fix [#37](https://github.com/adamrenklint/atom-block-cursor/issues/37) *Broken underline style* 6 | 7 | ## 0.13.2 8 | 9 | * Fix #33 *Deprecated selector in `block-cursor/styles/block-cursor.less`* 10 | 11 | ## 0.13.1 12 | * Fix #23 13 | 14 | ## 0.13.0 15 | * Rewrite. Breaks current configuration. See [README.md](README.md). 16 | * Disable `cursorLineFix` setting temporarily, because of a conflict with tile rendering introduced in Atom v0.209.0. 17 | 18 | ## 0.12.5 19 | * Fix bug where cursor blinking wasn't disabled properly 20 | * Add specs 21 | 22 | ## 0.12.4 23 | * Fix #14 24 | 25 | ## 0.12.3 26 | * Merge #12 27 | 28 | ## 0.12.2 29 | * Fix #11 by adding `useHardwareAcceleration` setting 30 | 31 | ## 0.12.1 32 | * Animate opacity when `secondaryColorAlpha` is `0`. Fixes #9 33 | * Fix #10 34 | 35 | ## 0.12.0 36 | * Rewrite 37 | * Separate scoped config observation into its own npm package 38 | 39 | ## 0.11.2 40 | * Fix #8 41 | 42 | ## 0.11.1 43 | * Fix some minor issues 44 | 45 | ## 0.11.0 46 | * Add support for scoped config 47 | 48 | ## 0.10.1 49 | * Fix readme 50 | * Some rewriting 51 | 52 | ## 0.10.0 53 | * Add separate alpha channel configs for both the color configs because the color picker on Linux doesn't support them. 54 | * Add fix for syntax themes with a `background-color` on the `.cursor-line` 55 | * Some rewriting 56 | 57 | ## 0.9.9 58 | * Fix #6 59 | 60 | ## 0.9.8 61 | * Don't set secondaryColor when changing blinkInterval 62 | 63 | ## 0.9.7 64 | * Better fix for #5 65 | 66 | ## 0.9.6 67 | * Fix #5 68 | 69 | ## 0.9.5 70 | * Fix cursor blink 71 | * Remove underscore dependency 72 | 73 | ## 0.9.4 74 | * Fix `blinkInterval` config description 75 | 76 | ## 0.9.3 77 | * Updated readme's `blink interval` section 78 | * Set default value for the `preview` field, to avoid a warning at activation 79 | * Workaround for disabling cursor blinking in `mini` editors 80 | 81 | ## 0.9.2 82 | * Fixed issue where package deactivation sometimes throws an exception 83 | 84 | ## 0.9.1 85 | * Changed `blinkInterval`'s default from 500 to 400 to match Atom's default behavior 86 | * Dispose of editor subscription on package deactivation 87 | 88 | ## 0.9.0 89 | * Added `blinkInterval` option 90 | * Removed `pulseDuration` maximum 91 | 92 | ## 0.8.1 93 | * Added preview field to the package settings 94 | 95 | ## 0.8.0 96 | * Added `cursorThickness` option 97 | 98 | ## 0.7.6 99 | * Use CompositeDisposable for the config subscriptions 100 | 101 | ## 0.7.5 102 | * Fix: remove cursorStyle element from the dom on package deactivation 103 | 104 | ## 0.7.4 105 | * Workaround for [#atom/5306](https://github.com/atom/atom/issues/5306) 106 | 107 | ## 0.7.3 108 | * Created a map between `cursorType` names/values for clearer options in the settings view select box 109 | 110 | ## 0.7.2 111 | * Show cursor examples in the settings view 112 | 113 | ## 0.7.1 114 | * Write less rules to the stylesheet 115 | 116 | ## 0.7.0 - Modernizing 117 | * Removed deprecated functions 118 | * atom.themes.removeStylesheet 119 | * atom.themes.requireStylesheet 120 | 121 | ## 0.6.1 122 | * Nicer looking readme 123 | 124 | ## 0.6.0 - Cursor galore 125 | * Added 3 types of cursors. See readme for images 126 | * I-beam 127 | * Bordered box 128 | * Underline 129 | 130 | ## 0.5.1 131 | * Updated readme 132 | 133 | ## 0.5.0 - Fancy pulse 134 | * Replaced the `enablePulse` option with `pulseDuration` option 135 | 136 | ## 0.4.6 137 | * Fix: make block-cursor.coffee look for vars.less instead of colors.less 138 | * Fix: make block-cursor.less look for vars.less instead of colors.less 139 | 140 | ## 0.4.5 141 | * Removed the block-cursor class from the workspaceView 142 | * Removed the block-cursor-pulse class from the workspaceView 143 | * Renamed styles/includes/colors.less -> styles/includes/vars.less 144 | 145 | ## 0.4.4 - Cleanup 146 | * Removed some console.logs 147 | 148 | ## 0.4.3 - Keeping track 149 | * Fixed false changelog information 150 | 151 | ## 0.4.2 - Config stuff 152 | * Changed the configuration mechanism, much easier to keep track of the config 153 | 154 | ## 0.4.1 - Cleanup 155 | * Removed some stray console.logs 156 | 157 | ## 0.4.0 158 | * Added pulse option 159 | 160 | ## 0.3.1 - Some fixes 161 | * Force cursor opacity to 1, also in blink-off state 162 | * Slightly changed the atom-text-editor[mini] selector 163 | 164 | ## 0.3.0 - Fancy blinking 165 | * Removed `cursorBlink` option 166 | * Renamed `cursorColor` option -> `primaryColor` 167 | * Added `secondaryColor` option 168 | 169 | ## 0.2.4 - Specs 170 | * Created specs for testing 171 | 172 | ## 0.2.3 - !important stuff 173 | * Made compatible with certain syntax themes that set !important on the border color of the cursor 174 | 175 | ## 0.2.2 - Grammar nazi 176 | * Fixed capitalization in config descriptions 177 | 178 | ## 0.2.1 - Blinking cursors 179 | * Fixed the `cursorBlink` config option 180 | 181 | ## 0.2.0 - Config color 182 | * Using new `color` type for the cursorColor option 183 | 184 | ## 0.1.1 - Readme fix 185 | * Fixed the image's url in the readme 186 | 187 | ## 0.1.0 - First Release 188 | * Every feature added 189 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Olmo Kramer 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Block cursor](https://raw.githubusercontent.com/olmokramer/atom-block-cursor/master/block-cursor.png) 2 | 3 | ## Configure 4 | 5 | Multiple cursor types can be registered in `config.cson`. The `block-cursor:new-custom-cursor` command can register a new cursor type. 6 | 7 | The following properties can be set for each cursor type: 8 | 9 | ```coffee 10 | selector: 'atom-text-editor' 11 | scopes: [ '*' ] 12 | blinkOn: 13 | backgroundColor: '#393939' 14 | borderStyle: 'none' 15 | borderColor: 'transparent' 16 | borderWidth: 0 17 | blinkOff: 18 | backgroundColor: 'transparent' 19 | borderStyle: 'none' 20 | borderColor: 'transparent' 21 | borderWidth: 0 22 | pulseDuration: 0 23 | cursorLineFix: false 24 | ``` 25 | 26 | ### selector 27 | 28 | Defines which `atom-text-editor` elements the cursor type should apply to. The selector should select an `atom-text-editor` element. 29 | 30 | ### scopes 31 | 32 | List of scopes that the cursor type should apply to. 33 | 34 | ### blinkOn.backgroundColor & blinkOff.backgroundColor 35 | 36 | The background color of the cursor in blink-on or blink-off state. 37 | 38 | ### blinkOn.borderStyle & blinkOff.borderStyle 39 | 40 | The border style of the cursor in blink-on or blink-off state. Can be one of the following: 41 | 42 | ![Block cursor](https://raw.githubusercontent.com/olmokramer/atom-block-cursor/master/cursor-bordered-box.png) 43 | 44 | ![Block cursor](https://raw.githubusercontent.com/olmokramer/atom-block-cursor/master/cursor-i-beam.png) 45 | 46 | ![Block cursor](https://raw.githubusercontent.com/olmokramer/atom-block-cursor/master/cursor-underline.png) 47 | 48 | `none` 49 | 50 | ### blinkOn.borderColor & blinkOff.borderColor 51 | 52 | The border color of the cursor in blink-on or blink-off state. 53 | 54 | ### blinkOn.borderWidth & blinkOff.borderWidth 55 | 56 | The border width of the cursor in blink-on or blink-off state. 57 | 58 | ### pulseDuration 59 | 60 | Pulse effect that fades the cursor from blink-on to blink-off state (instead of blinking). Set to 0 to disable. 61 | 62 | ![Block cursor](https://raw.githubusercontent.com/olmokramer/atom-block-cursor/master/cursor-pulse.gif) 63 | 64 | ### cursorLineFix 65 | 66 | When your syntax theme uses a `background-color` on `.cursor-line` - the line the cursor is on - the `block` cursor may become invisible. This is because the cursor has a `z-index` of `-1`, to make it render behind the text instead of above it. This fix sets the cursor's `z-index` to `1`, to make it render above the text, so you should use low `alpha` values for `primaryColor` and `secondaryColor` if you enable this fix. 67 | 68 | The `cursorLineFix` is currently ignored due to the new tile rendering of the editor that was introduced in Atom v0.209.0. It will always be set to `true`, to allow the cursor to render above the text, so make sure the background colors you use have low alpha values. Otherwise the character under the cursor will not be visible. 69 | 70 | You can also add this to your `styles.less` to disable the line highlight: 71 | ```less 72 | atom-text-editor.editor .lines .line.cursor-line { 73 | background-color: transparent; 74 | } 75 | ``` 76 | 77 | 78 | 79 | ### Example config 80 | 81 | ```coffee 82 | "block-cursor": 83 | # white cursor by default 84 | global: 85 | blinkOn: 86 | backgroundColor: "white" 87 | # dary grey cursor on [mini] editors 88 | mini: 89 | selector: "atom-text-editor[mini]" 90 | blinkOn: 91 | backgroundColor: "darkgrey" 92 | # box cursor when editor is not focused 93 | "no-focus": 94 | selector: "atom-text-editor:not(.is-focused)" 95 | blinkOn: 96 | backgroundColor: "transparent" 97 | borderColor: "white" 98 | borderStyle: "bordered-box" 99 | borderWidth: 1 100 | # red cursor in coffeescript 101 | "coffee-script": 102 | scopes: [ ".source.coffee" ], 103 | blinkOn: 104 | backgroundColor: "red" 105 | # lightgray cursor when using the one-dark-syntax theme 106 | "one-dark-syntax": 107 | selector: ".theme-one-dark-syntax atom-text-editor" 108 | blinkOn: 109 | backgroundColor: "lightgray" 110 | # darkgray cursor when using the one-light-syntax theme 111 | "one-light-syntax": 112 | selector: ".theme-one-light-syntax atom-text-editor" 113 | blinkOn: 114 | backgroundColor: "darkgray" 115 | ``` 116 | 117 | 118 | 119 | ## Commands 120 | 121 | ### `block-cursor:new-custom-cursor` 122 | 123 | This command adds a new cursor type that can be customised customise to `config.cson`, that can be configured from the settings view. By default it will be called `custom-X`, but it can be renamed to anything you like. 124 | 125 | 126 | ## Contribute 127 | 128 | Have other neat ideas for cursor customization? Found a bug? 129 | 130 | 1. :fork_and_knife: Fork the repo 131 | 2. :rocket: Make awesome things happen 132 | 3. :octocat: Create a pull request 133 | 134 | Or [create a new issue](https://github.com/adamrenklint/atom-block-cursor/issues/new) at the repository if you can't do it yourself. 135 | 136 | ## License and credits 137 | 138 | © 2015 Olmo Kramer
139 | Maintainer: [Adam Renklint](http://adamrenklint.com)
140 | [MIT license](LICENSE.md) 141 | -------------------------------------------------------------------------------- /block-cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamrenklint/atom-block-cursor/295bbf70df68295451c694c88079657feb74b05f/block-cursor.png -------------------------------------------------------------------------------- /cursor-bordered-box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamrenklint/atom-block-cursor/295bbf70df68295451c694c88079657feb74b05f/cursor-bordered-box.png -------------------------------------------------------------------------------- /cursor-i-beam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamrenklint/atom-block-cursor/295bbf70df68295451c694c88079657feb74b05f/cursor-i-beam.png -------------------------------------------------------------------------------- /cursor-pulse.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamrenklint/atom-block-cursor/295bbf70df68295451c694c88079657feb74b05f/cursor-pulse.gif -------------------------------------------------------------------------------- /cursor-underline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamrenklint/atom-block-cursor/295bbf70df68295451c694c88079657feb74b05f/cursor-underline.png -------------------------------------------------------------------------------- /lib/block-cursor.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | import 'object-assign-shim'; 3 | import {Disposable, CompositeDisposable} from 'atom'; 4 | 5 | // helper functions 6 | 7 | // get the key in namespace 8 | function getConfig(key, namespace = 'block-cursor') { 9 | return atom.config.get(key ? `${namespace}.${key}` : namespace); 10 | } 11 | 12 | // set the key in namespace 13 | function setConfig(key, value, namespace = 'block-cursor') { 14 | return atom.config.set(`${namespace}.${key}`, value); 15 | } 16 | 17 | // get a clone of the global config 18 | function getGlobalConfig() { 19 | var config = Object.assign({}, getConfig('global')); 20 | Object.assign(config.blinkOn, getConfig('global.blinkOn')); 21 | Object.assign(config.blinkOff, getConfig('global.blinkOff')); 22 | return config; 23 | } 24 | 25 | // convert a color to a string 26 | function toRGBAString(color) { 27 | if(typeof color == 'string') return color; 28 | if(typeof color.toRGBAString == 'function') return color.toRGBAString(); 29 | return `rgba(${color.red}, ${color.green}, ${color.blue}, ${color.alpha})`; 30 | } 31 | 32 | // private API 33 | 34 | // keep a reference to the stylesheet 35 | var style; 36 | 37 | // create a stylesheet element and 38 | // attach it to the DOM 39 | function setupStylesheet() { 40 | style = document.createElement('style'); 41 | style.type = 'text/css'; 42 | document.querySelector('head atom-styles').appendChild(style); 43 | 44 | // return a disposable for easy removal :) 45 | return new Disposable(() => { 46 | style.parentNode.removeChild(style); 47 | style = null; 48 | }); 49 | } 50 | 51 | // update the stylesheet when config changes 52 | function updateCursorStyles(config) { 53 | // clear stylesheet 54 | style.innerHTML = ''; 55 | for(let key of Object.keys(config)) { 56 | // and add styles for each cursor style 57 | style.innerHTML += cssForCursorStyle(config[key]); 58 | } 59 | } 60 | 61 | function cssForCursorStyle(cursorStyle) { 62 | // fill the cursor style with global as defaults 63 | cursorStyle = Object.assign(getGlobalConfig(), cursorStyle); 64 | var blinkOn = Object.assign({}, getConfig('global.blinkOn'), cursorStyle.blinkOn); 65 | var blinkOff = Object.assign({}, getConfig('global.blinkOff'), cursorStyle.blinkOff); 66 | var {selector, scopes, pulseDuration, cursorLineFix} = cursorStyle; 67 | 68 | // if cursor blinking is off, set the secondaryColor the same 69 | // as primaryColor to prevent cursor blinking in [mini] editors 70 | if(atom.packages.isPackageActive('cursor-blink-interval') && 71 | getConfig('cursorBlinkInterval', 'cursor-blink-interval') == 0) 72 | blinkOff = Object.assign({}, blinkOn); 73 | 74 | // blink on rule 75 | Object.assign(blinkOn, { 76 | selector: selectorForScopes(selector, scopes), 77 | properties: Object.assign({ 78 | // blink on background color 79 | 'background-color': toRGBAString(blinkOn.backgroundColor), 80 | // pulse animation duration 81 | 'transition-duration': `${pulseDuration}ms`, 82 | // cursor line fix 83 | // 'z-index': cursorLineFix ? 1 : -1 // @TODO: enable this when a solution is found for #20 84 | }, createBorderStyle(blinkOn)), 85 | }); 86 | // end blink on rule 87 | 88 | // blink off rule 89 | Object.assign(blinkOff, { 90 | selector: selectorForScopes(selector, scopes, true), 91 | properties: {}, 92 | }); 93 | if(blinkOff.backgroundColor.alpha == 0 && (blinkOff.borderWidth == 0 || 94 | blinkOff.borderStyle == 'none' || blinkOff.borderColor.alpha == 0)) { 95 | // better animation performance by animating opacity 96 | // if blink off cursor is invisible 97 | blinkOff.properties.opacity = 0; 98 | } else { 99 | Object.assign(blinkOff.properties, { 100 | // blink off background color 101 | 'background-color': toRGBAString(blinkOff.backgroundColor), 102 | }, createBorderStyle(blinkOff)); 103 | } 104 | // end blink off rule 105 | 106 | return createCSSRule(blinkOn) + createCSSRule(blinkOff); 107 | } 108 | 109 | // create a css properties object for given border properties 110 | function createBorderStyle({borderWidth, borderStyle, borderColor}) { 111 | var borderString = `${borderWidth}px solid ${toRGBAString(borderColor)}`; 112 | switch(borderStyle) { 113 | case 'bordered-box': 114 | // border on all sides 115 | return { border: borderString }; 116 | case 'i-beam': 117 | // border on left side 118 | return { border: 'none', 'border-left': borderString }; 119 | case 'underline': 120 | // border on bottom side 121 | return { border: 'none', 'border-bottom': borderString }; 122 | default: 123 | // no border 124 | return { border: 'none' }; 125 | } 126 | } 127 | 128 | // create a css rule from a selector and an 129 | // object containint propertyNames and values 130 | // of the form 131 | // { 132 | // : ; 133 | // : ; 134 | // ... 135 | // } 136 | 137 | function createCSSRule({selector, properties}) { 138 | return `${selector} { ${Object.keys(properties).map((key) => `${key}: ${properties[key]};`).join('')} }`; 139 | } 140 | 141 | // creates a css selector for the given scopes 142 | // @param base: selector that selects the atom-text-editor element 143 | // @param scopes: array of scopes to select 144 | // @param blinkOff: create a blink-off selector? 145 | function selectorForScopes(base, scopes, blinkOff = '') { 146 | var selectors = []; 147 | 148 | function grammarSelectorsForScopeName(scopeName) { 149 | return scopeName.split('.').map(scope => `[data-grammar~="${scope}"]`).join(''); 150 | } 151 | 152 | if(blinkOff) blinkOff = '.blink-off'; 153 | 154 | for(let scopeName of scopes) { 155 | let grammarSelectors = scopeName == '*' ? '' : grammarSelectorsForScopeName(scopeName); 156 | selectors.push(`${base}${grammarSelectors}.editor .cursors${blinkOff} .cursor`); 157 | } 158 | return selectors.join(','); 159 | } 160 | 161 | // add a custom cursor to the config. an easy 162 | // shortcut when you want to define a new cursor type 163 | function addCustomCursor() { 164 | var i = 0; 165 | while(getConfig(`custom-${i}`)) i++; 166 | setConfig(`custom-${i}`, getGlobalConfig()); 167 | } 168 | 169 | // public API 170 | 171 | // module.exports = BlockCursor = { 172 | const config = { 173 | global: { 174 | type: 'object', 175 | properties: { 176 | scopes: { 177 | type: 'array', 178 | default: [ '*' ], 179 | }, 180 | selector: { 181 | type: 'string', 182 | default: 'atom-text-editor', 183 | }, 184 | blinkOn: { 185 | type: 'object', 186 | properties: { 187 | backgroundColor: { 188 | type: 'color', 189 | default: '#393939', 190 | }, 191 | borderWidth: { 192 | type: 'integer', 193 | default: 1, 194 | minimum: 0, 195 | }, 196 | borderStyle: { 197 | type: 'string', 198 | default: 'none', 199 | enum: [ 200 | 'none', 201 | 'bordered-box', 202 | 'i-beam', 203 | 'underline', 204 | ], 205 | }, 206 | borderColor: { 207 | type: 'color', 208 | default: 'transparent', 209 | }, 210 | }, 211 | }, 212 | blinkOff: { 213 | type: 'object', 214 | properties: { 215 | backgroundColor: { 216 | type: 'color', 217 | default: 'transparent', 218 | }, 219 | borderWidth: { 220 | type: 'integer', 221 | default: 1, 222 | minimum: 0, 223 | }, 224 | borderStyle: { 225 | type: 'string', 226 | default: 'none', 227 | enum: [ 228 | 'none', 229 | 'bordered-box', 230 | 'i-beam', 231 | 'underline', 232 | ], 233 | }, 234 | borderColor: { 235 | type: 'color', 236 | default: 'transparent', 237 | }, 238 | }, 239 | }, 240 | pulseDuration: { 241 | type: 'integer', 242 | default: 0, 243 | minimum: 0, 244 | }, 245 | cursorLineFix: { 246 | description: 'Temporarily ignored (always true) because of an issue with the tile rendering introduced in Atom 0.209.0.', 247 | type: 'boolean', 248 | default: false, 249 | }, 250 | }, 251 | }, 252 | }; 253 | 254 | var disposables; 255 | 256 | function activate() { 257 | // wait for cursor-blink-interval package to activate 258 | // if it is loaded 259 | Promise.resolve( 260 | atom.packages.isPackageLoaded('cursor-blink-interval') && 261 | atom.packages.activatePackage('cursor-blink-interval') 262 | ).then(function go() { 263 | disposables = new CompositeDisposable( 264 | setupStylesheet(), 265 | atom.config.observe('block-cursor', updateCursorStyles), 266 | atom.commands.add('atom-workspace', 'block-cursor:new-custom-cursor', addCustomCursor) 267 | ); 268 | }).catch(error => { 269 | console.error(error.message); 270 | }); 271 | } 272 | 273 | function deactivate() { 274 | disposables.dispose(); 275 | disposables = null; 276 | } 277 | 278 | export {config, activate, deactivate}; 279 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "block-cursor", 3 | "main": "./lib/block-cursor", 4 | "version": "0.13.3", 5 | "description": "Fancy cursor customisation plugin", 6 | "keywords": [ 7 | "ui", 8 | "cursor" 9 | ], 10 | "repository": "git@github.com:adamrenklint/atom-block-cursor.git", 11 | "license": "MIT", 12 | "engines": { 13 | "atom": ">=1.13.0" 14 | }, 15 | "dependencies": { 16 | "object-assign-shim": "^1.0.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /styles/block-cursor.less: -------------------------------------------------------------------------------- 1 | atom-text-editor.editor .cursors .cursor { 2 | opacity: 1; 3 | color: transparent; 4 | background-color: transparent; 5 | border: none; 6 | transition-property: background-color, border-color, opacity; 7 | } 8 | 9 | atom-text-editor[mini]:not(.is-focused).editor .cursors .cursor { 10 | display: none; 11 | } 12 | --------------------------------------------------------------------------------