├── .travis.yml ├── .gitignore ├── atom-iex.gif ├── CHANGELOG.md ├── spec ├── iex-view-spec.coffee └── iex-spec.coffee ├── package.json ├── styles └── iex.less ├── lib ├── pty.coffee ├── TermView.coffee └── iex.coffee ├── keymaps └── iex.cson ├── LICENSE.md ├── menus └── iex.cson ├── elixir_src └── iex.exs └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | -------------------------------------------------------------------------------- /atom-iex.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/indiejames/atom-iex/HEAD/atom-iex.gif -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.1.0 - First Release 2 | * Every feature added 3 | * Every bug fixed 4 | -------------------------------------------------------------------------------- /spec/iex-view-spec.coffee: -------------------------------------------------------------------------------- 1 | IexView = require '../lib/iex-view' 2 | 3 | describe "IexView", -> 4 | it "has one valid test", -> 5 | expect("life").toBe "easy" 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iex", 3 | "main": "./lib/iex", 4 | "version": "0.10.0", 5 | "description": "Run an Elixir IEx (REPL) session in an Atom window.", 6 | "repository": "https://github.com/indiejames/atom-iex", 7 | "license": "MIT", 8 | "engines": { 9 | "atom": ">=1.0.0" 10 | }, 11 | "dependencies": { 12 | "atom-iex-term.js": "0.0.58", 13 | "fs-plus": "^2.2.3", 14 | "keypather": "^1.3.2", 15 | "pty.js": "^0.3.0", 16 | "atom-space-pen-views": "^2.0.3", 17 | "uuid": "^2.0.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /styles/iex.less: -------------------------------------------------------------------------------- 1 | // The ui-variables file is provided by base themes provided by Atom. 2 | // 3 | // See https://github.com/atom/atom-dark-ui/blob/master/stylesheets/ui-variables.less 4 | // for a full listing of what's available. 5 | @import "ui-variables"; 6 | 7 | .iex { 8 | .terminal { 9 | padding: 0; 10 | 11 | > div { 12 | white-space: pre; 13 | > span { 14 | display: inline-block; 15 | line-height: inherit; 16 | height: inherit; 17 | font-weight: normal !important; 18 | } 19 | } 20 | 21 | .terminal-cursor { 22 | background-color: #fff; 23 | } 24 | 25 | span { 26 | white-space: pre; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/pty.coffee: -------------------------------------------------------------------------------- 1 | # from atom/terminal to reduce cpu usage 2 | pty = require 'pty.js' 3 | 4 | module.exports = (ptyCwd, args) -> 5 | callback = @async() 6 | # if sh 7 | # shell = sh 8 | # else 9 | # if process.platform is 'win32' 10 | # path = require 'path' 11 | # shell = path.resolve(process.env.SystemRoot, 'WindowsPowerShell', 'v1.0', 'powershell.exe') 12 | # else 13 | shell = process.env.SHELL 14 | 15 | cols = 80 16 | rows = 30 17 | 18 | ptyProcess = pty.fork shell, args, 19 | name: 'xterm-256color' 20 | cols: cols 21 | rows: rows 22 | cwd: ptyCwd 23 | env: process.env 24 | 25 | ptyProcess.on 'data', (data) -> emit('iex:data', data) 26 | ptyProcess.on 'exit', -> 27 | emit('iex:exit') 28 | callback() 29 | 30 | process.on 'message', ({event, cols, rows, text}={}) -> 31 | switch event 32 | when 'resize' then ptyProcess.resize(cols, rows) 33 | when 'input' then ptyProcess.write(text) 34 | -------------------------------------------------------------------------------- /keymaps/iex.cson: -------------------------------------------------------------------------------- 1 | # Keybindings require three things to be fully defined: A selector that is 2 | # matched against the focused element, the keystroke and the command to 3 | # execute. 4 | # 5 | # Below is a basic keybinding which registers on all platforms by applying to 6 | # the root workspace element. 7 | 8 | # For more detailed documentation see 9 | # https://atom.io/docs/latest/advanced/keymaps 10 | 11 | 'atom-workspace': 12 | 'cmd-alt-l': 'iex:open' 13 | 'cmd-alt-l down': 'iex:open-split-down' 14 | 'cmd-alt-l up': 'iex:open-split-up' 15 | 'cmd-alt-l left': 'iex:open-split-left' 16 | 'cmd-alt-l right': 'iex:open-split-right' 17 | 'cmd-alt-e': 'iex:reset' 18 | 'cmd-alt-a': 'iex:run-all-tests' 19 | 'cmd-alt-p': 'iex:pretty-print' 20 | 21 | 'atom-text-editor': 22 | 'cmd-alt-h': 'iex:help' 23 | 'cmd-alt-o': 'iex:gotoDefinition' 24 | 'cmd-alt-x': 'iex:run-tests' 25 | 'cmd-alt-j': 'iex:run-test' 26 | 'cmd-alt-b': 'iex:pipe' 27 | 'cmd-alt-y': 'iex:say-yes' 28 | 29 | '.iex': 30 | 'cmd-v': 'iex:paste' 31 | 'ctrl-v': 'iex:paste' 32 | 'cmd-c': 'iex:copy' 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 James Norton 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 | -------------------------------------------------------------------------------- /menus/iex.cson: -------------------------------------------------------------------------------- 1 | # See https://atom.io/docs/latest/creating-a-package#menus for more details 2 | 'context-menu': 3 | '.iex': [ 4 | {'label': 'Copy', 'command': 'iex:copy'} 5 | {'label': 'Paste', 'command': 'iex:paste'} 6 | ] 7 | 'menu': [ 8 | { 9 | 'label': 'Packages' 10 | 'submenu': [ 11 | 'label': 'iex' 12 | 'submenu': [ 13 | 14 | {'label': 'Open IEx session in New Tab', 'command': 'iex:open'} 15 | {'label': 'Open IEx session in Bottom Pane', 'command': 'iex:open-split-down'} 16 | {'label': 'Open IEx session in Top Pane', 'command': 'iex:open-split-down'} 17 | {'label': 'Open IEx session in Right Pane', 'command': 'iex:open-split-down'} 18 | {'label': 'Open IEx session in Left Pane', 'command': 'iex:open-split-down'} 19 | {'label': 'Jump to definition', 'command': 'iex:gotoDefinition'} 20 | {'label': 'Print help for function', 'command': 'iex:help'} 21 | {'label': 'Run all tests', 'command': 'iex:run-all-tests'} 22 | {'label': 'Run all tests in pane', 'command': 'iex:run-tests'} 23 | {'label': 'Run test', 'command': 'iex:run-test'} 24 | {'label': 'Reset', 'command': 'iex:reset'} 25 | {'label': 'Execute selected in IEx', 'command': 'iex:pipe'} 26 | ] 27 | ] 28 | } 29 | ] 30 | -------------------------------------------------------------------------------- /elixir_src/iex.exs: -------------------------------------------------------------------------------- 1 | defmodule AtomIEx do 2 | @moduledoc "Helper functions to support interaction with IEx using the iex 3 | package for the Atom editor" 4 | 5 | @doc "Reset the application" 6 | def reset do 7 | Mix.Task.reenable "compile.elixir" 8 | try do 9 | Application.stop(Mix.Project.config[:app]); 10 | Mix.Task.run "compile.elixir"; 11 | Application.start(Mix.Project.config[:app], :permanent) 12 | catch; 13 | :exit, _ -> "Application failed to start" 14 | end 15 | :ok 16 | end 17 | 18 | @doc "Run all the tests defined in the application" 19 | def run_all_tests do 20 | {rval, _} = System.cmd("mix", ["test", "--color"], []) 21 | IO.puts rval 22 | end 23 | 24 | @doc "Run the currently open test file" 25 | def run_test(file) do 26 | {rval, _} = System.cmd("mix", ["test", "--color", file]) 27 | IO.puts rval 28 | end 29 | 30 | @doc "Run the currently selected test" 31 | def run_test(file, line_num) do 32 | {rval, _} = System.cmd("mix", ["test", "--color", "#{file}:#{line_num}"]) 33 | IO.puts rval 34 | end 35 | 36 | @doc "Get file and line of a module definition" 37 | def get_file_and_line(module) do 38 | file = to_string(module.__info__(:compile)[:source]) 39 | code_docs = Code.get_docs(module, :moduledoc) 40 | line_num = elem(code_docs, 0) 41 | "#{module} - #{file}:#{line_num}" 42 | end 43 | 44 | @doc "Get file and line of function definition" 45 | def get_file_and_line(module, func) do 46 | file = to_string(module.__info__(:compile)[:source]) 47 | code_docs = Code.get_docs(module, :all)[:docs] 48 | #line_num = List.key_find(code_docs, ) 49 | entry = Enum.find(code_docs, fn(x) -> elem(x, 0) |> elem(0) == func end) 50 | line_num = elem(entry, 1) 51 | "#{module}.#{func} - #{file}:#{line_num}" 52 | end 53 | 54 | defmodule Comment do 55 | @moduledoc "Provides a 'comment' macro to allow blocks of code to be ignored 56 | to facilitate running them as small tests in IEx during interactive 57 | development. 58 | 59 | Usage: 60 | ``` 61 | comment do 62 | some code 63 | end 64 | ```" 65 | defmacro comment(_expr) do 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /spec/iex-spec.coffee: -------------------------------------------------------------------------------- 1 | Iex = require '../lib/iex' 2 | 3 | # Use the command `window:run-package-specs` (cmd-alt-ctrl-p) to run specs. 4 | # 5 | # To run a specific `it` or `describe` block add an `f` to the front (e.g. `fit` 6 | # or `fdescribe`). Remove the `f` to unfocus the block. 7 | 8 | describe "Iex", -> 9 | [workspaceElement, activationPromise] = [] 10 | 11 | beforeEach -> 12 | workspaceElement = atom.views.getView(atom.workspace) 13 | activationPromise = atom.packages.activatePackage('iex') 14 | 15 | describe "when the iex:toggle event is triggered", -> 16 | it "hides and shows the modal panel", -> 17 | # Before the activation event the view is not on the DOM, and no panel 18 | # has been created 19 | expect(workspaceElement.querySelector('.iex')).not.toExist() 20 | 21 | # This is an activation event, triggering it will cause the package to be 22 | # activated. 23 | atom.commands.dispatch workspaceElement, 'iex:toggle' 24 | 25 | waitsForPromise -> 26 | activationPromise 27 | 28 | runs -> 29 | expect(workspaceElement.querySelector('.iex')).toExist() 30 | 31 | iexElement = workspaceElement.querySelector('.iex') 32 | expect(iexElement).toExist() 33 | 34 | iexPanel = atom.workspace.panelForItem(iexElement) 35 | expect(iexPanel.isVisible()).toBe true 36 | atom.commands.dispatch workspaceElement, 'iex:toggle' 37 | expect(iexPanel.isVisible()).toBe false 38 | 39 | it "hides and shows the view", -> 40 | # This test shows you an integration test testing at the view level. 41 | 42 | # Attaching the workspaceElement to the DOM is required to allow the 43 | # `toBeVisible()` matchers to work. Anything testing visibility or focus 44 | # requires that the workspaceElement is on the DOM. Tests that attach the 45 | # workspaceElement to the DOM are generally slower than those off DOM. 46 | jasmine.attachToDOM(workspaceElement) 47 | 48 | expect(workspaceElement.querySelector('.iex')).not.toExist() 49 | 50 | # This is an activation event, triggering it causes the package to be 51 | # activated. 52 | atom.commands.dispatch workspaceElement, 'iex:toggle' 53 | 54 | waitsForPromise -> 55 | activationPromise 56 | 57 | runs -> 58 | # Now we can test for view visibility 59 | iexElement = workspaceElement.querySelector('.iex') 60 | expect(iexElement).toBeVisible() 61 | atom.commands.dispatch workspaceElement, 'iex:toggle' 62 | expect(iexElement).not.toBeVisible() 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iex package 2 | 3 | This package provides Elixir developers with the ability to run an Elixir IEx 4 | (REPL) session in an Atom window. It has only been tested on OS X and is 5 | unlikely to work properly (or at all) on other platforms. 6 | 7 |  8 | 9 | 10 | ### Installation 11 | 12 | ``` 13 | apm install iex 14 | ``` 15 | 16 | It is _highly recommended_ that you add the key bindings below. These can be 17 | customized as desired. They are not set by default to avoid conflicts with 18 | other packages. 19 | 20 | ### Features 21 | 22 | Aside from typing directly in the IEx session, the plugin provides actions 23 | to improve workflow: 24 | 25 | * Reset the project, restarting the application and compiling any files that 26 | have changed since the last restart 27 | * Run all tests in the project 28 | * Run all tests in the currently open editor 29 | * Run the test in the open editor in which the cursor resides 30 | * Execute the currently selected text 31 | 32 | These actions depend on `mix`, so they only work for `mix` generated projects 33 | and require a `mix.exs` file at the top level. 34 | 35 | ### Key Bindings 36 | 37 | Customizing Key Bindings: 38 | 39 | ```cson 40 | 'atom-workspace': 41 | 'cmd-alt-l': 'iex:open' 42 | 'cmd-alt-l down': 'iex:open-split-down' 43 | 'cmd-alt-l up': 'iex:open-split-up' 44 | 'cmd-alt-l left': 'iex:open-split-left' 45 | 'cmd-alt-l right': 'iex:open-split-right' 46 | 'cmd-alt-e': 'iex:reset' 47 | 'cmd-alt-a': 'iex:run-all-tests' 48 | 'cmd-alt-p': 'iex:pretty-print' 49 | 50 | 'atom-text-editor': 51 | 'cmd-alt-h': 'iex:help' 52 | 'cmd-alt-o': 'iex:gotoDefinition' 53 | 'cmd-alt-x': 'iex:run-tests' 54 | 'cmd-alt-j': 'iex:run-test' 55 | 'cmd-alt-b': 'iex:pipe' 56 | ``` 57 | 58 | Adding these will provide the following: 59 | 60 | #### Key Bindings and Events 61 | 62 | | key binding | event | action | 63 | | ----------- | ----- | ------ | 64 | | `cmd + alt + l` | `iex:open` | Opens new IEx in new tab pane | 65 | | `cmd + alt + l down` | `iex:open-split-up` | Opens new IEx tab pane in up split | 66 | | `cmd + alt + l right` | `iex:open-split-right` | Opens new IEx tab pane in right split | 67 | | `cmd + alt + l down` | `iex:open-split-down` | Opens new IEx tab pane in down split | 68 | | `cmd + alt + l left` | `iex:open-split-left` | Opens new IEx tab pane in left split | 69 | | `cmd + alt + e` | `iex:reset` | Stops the application, compiles any changed files with mix, then restarts the application. | 70 | | `cmd + alt + a` | `iex:run-all-tests` | Run all the test in the project | 71 | | `cmd + alt + x` | `iex:run-tests` | Run all the tests in the active editor | 72 | | `cmd + alt + j` | `iex:run-test` | Run the test in which the cursor lies | 73 | | `cmd + alt + h` | `iex:help` | Print the docstring for the function or module under the cursor | 74 | | `cmd + alt + o` | `iex:gotoDefinition`| Jump to the definition of the function or module under the cursor | 75 | | `cmd + alt + b` | `iex:pipe` | Pipe the currently selected text to the REPL and execute it | 76 | | `cmd + alt + p` | `iex:pretty-print` | Pretty print the last evaluated expression | 77 | 78 | ### Fonts 79 | The REPL defaults to using the same font family/size as Atom. Independent settings for the REPL will be available in the next release. 80 | 81 | ### Contributions 82 | 83 | This package is originally based on the [Term2 Atom package](https://atom.io/packages/term2) with heavy modifications. Feel free to submit bugs or issue pull requests. 84 | -------------------------------------------------------------------------------- /lib/TermView.coffee: -------------------------------------------------------------------------------- 1 | util = require 'util' 2 | path = require 'path' 3 | os = require 'os' 4 | fs = require 'fs-plus' 5 | uuid = require 'uuid' 6 | 7 | Terminal = require 'atom-iex-term.js' 8 | 9 | keypather = do require 'keypather' 10 | 11 | {Task, CompositeDisposable} = require 'atom' 12 | {$, View, ScrollView} = require 'atom-space-pen-views' 13 | 14 | uuids = [] 15 | 16 | last = (str)-> str[str.length-1] 17 | 18 | generateUUID = ()-> 19 | new_id = uuid.v1().substring(0,4) 20 | while new_id in uuids 21 | new_id = uuid.v1().substring(0,4) 22 | uuids.push new_id 23 | new_id 24 | 25 | getMixFilePath = ()-> 26 | mixPath = null 27 | for projectPath in atom.project.getPaths() 28 | do (projectPath) -> 29 | if projectPath && fs.existsSync(path.join(projectPath, 'mix.exs')) 30 | mixPath = path.join(projectPath, 'mix.exs') 31 | return 32 | mixPath 33 | 34 | renderTemplate = (template, data)-> 35 | vars = Object.keys data 36 | vars.reduce (_template, key)-> 37 | _template.split(///\{\{\s*#{key}\s*\}\}///) 38 | .join data[key] 39 | , template.toString() 40 | 41 | class TermView extends View 42 | 43 | tabindex: -1 44 | 45 | @content: -> 46 | @div class: 'iex', click: 'click' 47 | 48 | constructor: (@opts={})-> 49 | @opts.shell = process.env.SHELL or 'bash' 50 | @opts.shellArguments or= '' 51 | 52 | editorPath = keypather.get atom, 'workspace.getEditorViews[0].getEditor().getPath()' 53 | @opts.cwd = @opts.cwd or atom.project.getPaths()[0] or editorPath or process.env.HOME 54 | super 55 | 56 | applyStyle: -> 57 | # remove background color in favor of the atom background 58 | @term.element.style.background = null 59 | @term.element.style.fontFamily = ( 60 | @opts.fontFamily or 61 | atom.config.get('editor.fontFamily') or 62 | # (Atom doesn't return a default value if there is none) 63 | # so we use a poor fallback 64 | "monospace" 65 | ) 66 | # Atom returns a default for fontSize 67 | @term.element.style.fontSize = ( 68 | @opts.fontSize or 69 | atom.config.get('editor.fontSize') 70 | ) + "px" 71 | 72 | forkPtyProcess: (args=[])-> 73 | processPath = require.resolve './pty' 74 | projectPath = atom.project.getPaths()[0] ? '~' 75 | Task.once processPath, fs.absolute(projectPath), args 76 | # TODO - try switching back to pty.js to see if it fixes the backspace issue 77 | 78 | initialize: (@state)-> 79 | @shell_stdout_history = [] 80 | iexSrcPath = atom.packages.resolvePackagePath("iex") + "/elixir_src/iex.exs" 81 | {cols, rows} = @getDimensions() 82 | {cwd, shell, shellArguments, runCommand, colors, cursorBlink, scrollback} = @opts 83 | new_id = generateUUID() 84 | iexPath = atom.config.get('iex.iexExecutablePath') 85 | args = ["-l", "-c", iexPath + " --sname IEX-" + new_id + " -r " + iexSrcPath] 86 | mixPath = getMixFilePath() 87 | # assume mix file is at top level 88 | if mixPath 89 | file_str = fs.readFileSync(mixPath, {"encoding": "utf-8"}) 90 | phoenix_str = "" 91 | if atom.config.get('iex.startPhoenixServer') && file_str.match(/applications.*:phoenix/g) 92 | phoenix_str = " phoenix.server" 93 | args = ["-l", "-c", iexPath + " --sname IEX-" + new_id + " -r " + iexSrcPath + " -S mix" + phoenix_str] 94 | 95 | @term = term = new Terminal { 96 | useStyle: no 97 | screenKeys: no 98 | colors: colorsArray 99 | cursorBlink, scrollback, cols, rows 100 | } 101 | 102 | @ptyProcess = @forkPtyProcess args 103 | # capture output from the child process (shell) 104 | @ptyProcess.on 'iex:data', (data) => 105 | @shell_stdout_history.push data 106 | if @shell_stdout_history.length > 10 107 | @shell_stdout_history = @shell_stdout_history.slice(-10) 108 | @term.write data 109 | @ptyProcess.on 'iex:exit', (data) => @destroy() 110 | 111 | colorsArray = (colorCode for colorName, colorCode of colors) 112 | 113 | term.end = => @destroy() 114 | 115 | term.on "copy", (text)=> @copy(text) 116 | 117 | term.on "data", (data)=> @input data 118 | term.open this.get(0) 119 | 120 | @input "#{runCommand}#{os.EOL}" if runCommand 121 | term.focus() 122 | @applyStyle() 123 | @attachEvents() 124 | @resizeToPane() 125 | 126 | 127 | focus: -> 128 | @resizeToPane() 129 | @focusTerm() 130 | #super 131 | 132 | focusTerm: -> 133 | @term.element.focus() 134 | @term.focus() 135 | 136 | onActivePaneItemChanged: (activeItem) => 137 | if (activeItem && activeItem.items.length == 1 && activeItem.items[0] == this) 138 | @focus() 139 | 140 | input: (data) -> 141 | @ptyProcess.send event: 'input', text: data 142 | 143 | resize: (cols, rows) -> 144 | try 145 | @ptyProcess.send {event: 'resize', rows, cols} 146 | catch error 147 | console.log error 148 | 149 | titleVars: -> 150 | bashName: last @opts.shell.split '/' 151 | hostName: os.hostname() 152 | platform: process.platform 153 | home : process.env.HOME 154 | 155 | getTitle: -> 156 | @vars = @titleVars() 157 | titleTemplate = @opts.titleTemplate or "({{ bashName }})" 158 | renderTemplate titleTemplate, @vars 159 | 160 | getIconName: -> 161 | "terminal" 162 | 163 | attachEvents: -> 164 | @resizeToPane = @resizeToPane.bind this 165 | @attachResizeEvents() 166 | # Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable 167 | @subscriptions = new CompositeDisposable 168 | 169 | # Register commands 170 | @subscriptions.add atom.commands.add '.iex', 'iex:paste': => @paste() 171 | @subscriptions.add atom.commands.add '.iex', 'iex:copy': => @copy() 172 | @subscriptions.add atom.workspace.onDidChangeActivePane(@onActivePaneItemChanged) 173 | #atom.workspace.onDidChangeActivePaneItem (item)=> @onActivePaneItemChanged(item) 174 | 175 | click: (evt, element) -> 176 | @focus() 177 | 178 | paste: -> 179 | try 180 | @input atom.clipboard.read() 181 | catch error 182 | 183 | copy: -> 184 | if @term._selected # term.js visual mode selections 185 | textarea = @term.getCopyTextarea() 186 | text = @term.grabText( 187 | @term._selected.x1, @term._selected.x2, 188 | @term._selected.y1, @term._selected.y2) 189 | else # fallback to DOM-based selections 190 | text = @term.context.getSelection().toString() 191 | rawText = @term.context.getSelection().toString() 192 | rawLines = rawText.split(/\r?\n/g) 193 | lines = rawLines.map (line) -> 194 | line.replace(/\s/g, " ").trimRight() 195 | text = lines.join("\n") 196 | atom.clipboard.write text 197 | 198 | attachResizeEvents: -> 199 | setTimeout (=> @resizeToPane()), 10 200 | @on 'focus', @focus 201 | $(window).on 'resize', => @resizeToPane() 202 | 203 | detachResizeEvents: -> 204 | @off 'focus', @focus 205 | $(window).off 'resize' 206 | 207 | resizeToPane: -> 208 | {cols, rows} = @getDimensions() 209 | return unless cols > 0 and rows > 0 210 | return unless @term 211 | return if @term.rows is rows and @term.cols is cols 212 | 213 | @resize cols, rows 214 | @term.resize cols, rows 215 | atom.views.getView(atom.workspace).style.overflow = 'visible' 216 | 217 | getDimensions: -> 218 | fakeRow = $("