Merge branch 'master' into ns-mb-detangle-editor

This commit is contained in:
Max Brunsfeld
2016-08-05 09:39:43 -07:00
23 changed files with 317 additions and 277 deletions

View File

@@ -5,11 +5,12 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
## Requirements
* OS with 64-bit or 32-bit architecture
* C++ toolchain
* C++11 toolchain
* [Git](https://git-scm.com/)
* [Node.js](https://nodejs.org/en/download/) (0.10.x or above)
* [npm](https://www.npmjs.com/) v1.4.x or above (automatically bundled with Node.js)
* Node.js (4.x or above) (Can be installed via [nvm](https://github.com/creationix/nvm)).
* [npm](https://www.npmjs.com/) v3.10.5 or above (automatically bundled with Node.js)
* `npm -v` to check the version.
* `npm install -g npm` to upgrade if necessary.
* `npm config set python /usr/bin/python2 -g` to ensure that gyp uses python2.
* You might need to run this command as `sudo`, depending on how you have set up [npm](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager#ubuntu-mint-elementary-os).
* development headers for [GNOME Keyring](https://wiki.gnome.org/Projects/GnomeKeyring)
@@ -17,10 +18,18 @@ Ubuntu LTS 12.04 64-bit is the recommended platform.
### Ubuntu / Debian
* `sudo apt-get install build-essential git libgnome-keyring-dev fakeroot`
* Instructions for [Node.js](https://github.com/nodejs/node-v0.x-archive/wiki/Installing-Node.js-via-package-manager#debian-and-ubuntu-based-linux-distributions).
* Make sure the command `node` is available after Node.js installation (some systems install it as `nodejs`).
* Use `which node` to check if it is available.
* Use `sudo update-alternatives --install /usr/bin/node node /usr/bin/nodejs 10` to update it.
* Install Node.js and npm:
* Install [nvm](https://github.com/creationix/nvm).
* Run `nvm install 4` to install Node 4.x.
* Run `npm install -g npm` to upgrade to the latest npm.
* You may need to install a newer C++ compiler with C++11 support if script/bootstrap has errors:
```sh
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install gcc-5 g++-5
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 80 --slave /usr/bin/g++ g++ /usr/bin/g++-5
sudo update-alternatives --config gcc # choose gcc-5 from the list
```
### Fedora / CentOS / RHEL

View File

@@ -58,7 +58,7 @@
"sinon": "1.17.4",
"source-map-support": "^0.3.2",
"temp": "0.8.1",
"text-buffer": "9.2.3",
"text-buffer": "9.2.6",
"typescript-simple": "1.0.0",
"underscore-plus": "^1.6.6",
"winreg": "^1.2.1",
@@ -87,13 +87,13 @@
"autoflow": "0.27.0",
"autosave": "0.23.1",
"background-tips": "0.26.1",
"bookmarks": "0.41.0",
"bookmarks": "0.41.1",
"bracket-matcher": "0.82.1",
"command-palette": "0.38.0",
"deprecation-cop": "0.54.1",
"dev-live-reload": "0.47.0",
"encoding-selector": "0.22.0",
"exception-reporting": "0.38.1",
"exception-reporting": "0.38.2",
"find-and-replace": "0.201.0",
"fuzzy-finder": "1.3.0",
"git-diff": "1.1.0",

View File

@@ -197,6 +197,21 @@ class AtomReporter
time = "0#{time}" if time.length < 3
@time.textContent = "#{time[0...-2]}.#{time[-2..]}s"
specTitle: (spec) ->
parentDescs = []
s = spec.suite
while s
parentDescs.unshift(s.description)
s = s.parentSuite
suiteString = ""
indent = ""
for desc in parentDescs
suiteString += indent + desc + "\n"
indent += " "
"#{suiteString} #{indent} it #{spec.description}"
addSpecs: (specs) ->
coreSpecs = 0
bundledPackageSpecs = 0
@@ -204,6 +219,7 @@ class AtomReporter
for spec in specs
symbol = document.createElement('li')
symbol.setAttribute('id', "spec-summary-#{spec.id}")
symbol.setAttribute('title', @specTitle(spec))
symbol.className = "spec-summary pending"
switch spec.specType
when 'core'

View File

@@ -1,159 +1,85 @@
'use babel'
/** @babel */
/* eslint-env jasmine */
import child_process from 'child_process'
import environmentHelpers from '../src/environment-helpers'
import os from 'os'
import updateProcessEnv from '../src/update-process-env'
import dedent from 'dedent'
describe('Environment handling', () => {
let originalEnv
let options
describe('updateProcessEnv(launchEnv)', function () {
let originalProcessEnv, originalProcessPlatform
beforeEach(() => {
originalEnv = process.env
delete process._originalEnv
options = {
platform: process.platform,
env: Object.assign({}, process.env)
}
beforeEach(function () {
originalProcessEnv = process.env
originalProcessPlatform = process.platform
process.env = {}
})
afterEach(() => {
process.env = originalEnv
delete process._originalEnv
afterEach(function () {
process.env = originalProcessEnv
process.platform = originalProcessPlatform
})
describe('on macOS, when PWD is not set', () => {
beforeEach(() => {
options.platform = 'darwin'
})
describe('when the launch environment appears to come from a shell', function () {
it('updates process.env to match the launch environment', function () {
process.env = {
WILL_BE_DELETED: 'hi',
NODE_ENV: 'the-node-env',
NODE_PATH: '/the/node/path',
}
const initialProcessEnv = process.env
describe('needsPatching', () => {
it('returns true if PWD is unset', () => {
delete options.env.PWD
expect(environmentHelpers.needsPatching(options)).toBe(true)
options.env.PWD = undefined
expect(environmentHelpers.needsPatching(options)).toBe(true)
options.env.PWD = null
expect(environmentHelpers.needsPatching(options)).toBe(true)
options.env.PWD = false
expect(environmentHelpers.needsPatching(options)).toBe(true)
updateProcessEnv({PWD: '/the/dir', KEY1: 'value1', KEY2: 'value2'})
expect(process.env).toEqual({
PWD: '/the/dir',
KEY1: 'value1',
KEY2: 'value2',
NODE_ENV: 'the-node-env',
NODE_PATH: '/the/node/path',
})
it('returns false if PWD is set', () => {
options.env.PWD = 'xterm'
expect(environmentHelpers.needsPatching(options)).toBe(false)
})
})
describe('normalize', () => {
it('changes process.env if PWD is unset', () => {
if (process.platform === 'win32') {
return
}
delete options.env.PWD
environmentHelpers.normalize(options)
expect(process._originalEnv).toBeDefined()
expect(process._originalEnv).toBeTruthy()
expect(process.env).toBeDefined()
expect(process.env).toBeTruthy()
expect(process.env.PWD).toBeDefined()
expect(process.env.PWD).toBeTruthy()
expect(process.env.PATH).toBeDefined()
expect(process.env.PATH).toBeTruthy()
expect(process.env.ATOM_HOME).toBeDefined()
expect(process.env.ATOM_HOME).toBeTruthy()
})
// See #11302. On Windows, `process.env` is a magic object that offers
// case-insensitive environment variable matching, so we cannot replace it
// with another object.
expect(process.env).toBe(initialProcessEnv)
})
})
describe('on a platform other than macOS', () => {
beforeEach(() => {
options.platform = 'penguin'
})
describe('when the launch environment does not come from a shell', function () {
describe('on osx', function () {
it('updates process.env to match the environment in the user\'s login shell', function () {
process.platform = 'darwin'
process.env.SHELL = '/my/custom/bash'
describe('needsPatching', () => {
it('returns false if PWD is set or unset', () => {
delete options.env.PWD
expect(environmentHelpers.needsPatching(options)).toBe(false)
options.env.PWD = undefined
expect(environmentHelpers.needsPatching(options)).toBe(false)
options.env.PWD = null
expect(environmentHelpers.needsPatching(options)).toBe(false)
options.env.PWD = false
expect(environmentHelpers.needsPatching(options)).toBe(false)
options.env.PWD = '/'
expect(environmentHelpers.needsPatching(options)).toBe(false)
})
it('returns false for linux', () => {
options.platform = 'linux'
options.PWD = '/'
expect(environmentHelpers.needsPatching(options)).toBe(false)
})
it('returns false for windows', () => {
options.platform = 'win32'
options.PWD = 'c:\\'
expect(environmentHelpers.needsPatching(options)).toBe(false)
})
})
describe('normalize', () => {
it('does not change the environment', () => {
if (process.platform === 'win32') {
return
}
delete options.env.PWD
environmentHelpers.normalize(options)
expect(process._originalEnv).toBeUndefined()
expect(process.env).toBeDefined()
expect(process.env).toBeTruthy()
expect(process.env.PATH).toBeDefined()
expect(process.env.PATH).toBeTruthy()
expect(process.env.PWD).toBeUndefined()
expect(process.env.PATH).toBe(originalEnv.PATH)
expect(process.env.ATOM_HOME).toBeDefined()
expect(process.env.ATOM_HOME).toBeTruthy()
})
})
})
describe('getFromShell', () => {
describe('when things are configured properly', () => {
beforeEach(() => {
spyOn(child_process, 'spawnSync').andReturn({
stdout: 'FOO=BAR' + os.EOL + 'TERM=xterm-something' + os.EOL +
'PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path'
stdout: dedent`
FOO=BAR=BAZ=QUUX
TERM=xterm-something
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path
`
})
})
it('returns an object containing the information from the user\'s shell environment', () => {
let env = environmentHelpers.getFromShell()
expect(env.FOO).toEqual('BAR')
expect(env.TERM).toEqual('xterm-something')
expect(env.PATH).toEqual('/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path')
updateProcessEnv(process.env)
expect(child_process.spawnSync.mostRecentCall.args[0]).toBe('/my/custom/bash')
expect(process.env).toEqual({
FOO: 'BAR=BAZ=QUUX',
TERM: 'xterm-something',
PATH: '/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path'
})
// Doesn't error
updateProcessEnv(null)
})
})
describe('when an error occurs launching the shell', () => {
beforeEach(() => {
spyOn(child_process, 'spawnSync').andReturn({
error: new Error('testing when an error occurs')
})
})
describe('not on osx', function () {
it('does not update process.env', function () {
process.platform = 'win32'
spyOn(child_process, 'spawnSync')
process.env = {FOO: 'bar'}
it('returns undefined', () => {
expect(environmentHelpers.getFromShell()).toBeUndefined()
})
it('leaves the environment as-is when normalize() is called', () => {
options.platform = 'darwin'
delete options.env.PWD
expect(environmentHelpers.needsPatching(options)).toBe(true)
environmentHelpers.normalize(options)
expect(process.env).toBeDefined()
expect(process._originalEnv).toBeUndefined()
updateProcessEnv(process.env)
expect(child_process.spawnSync).not.toHaveBeenCalled()
expect(process.env).toEqual({FOO: 'bar'})
})
})
})

View File

@@ -5600,6 +5600,13 @@ describe "TextEditor", ->
rangeIsReversed: false
}
it "does not throw errors after the marker's containing layer is destroyed", ->
layer = editor.addMarkerLayer()
marker = layer.markBufferRange([[2, 4], [6, 8]])
decoration = editor.decorateMarker(marker, type: 'highlight', class: 'foo')
layer.destroy()
editor.decorationsStateForScreenRowRange(0, 5)
describe "::decorateMarkerLayer", ->
it "based on the markers in the layer, includes multiple decoration objects with the same properties and different ranges in the object returned from ::decorationsStateForScreenRowRange", ->
layer1 = editor.getBuffer().addMarkerLayer()
@@ -5753,6 +5760,17 @@ describe "TextEditor", ->
editor.setEditorWidthInChars(10)
expect(editor.lineTextForScreenRow(0)).toBe 'var '
describe "the softWrapHangingIndent setting", ->
it "controls how much extra indentation is applied to soft-wrapped lines", ->
editor.setText('123456789')
editor.setEditorWidthInChars(8)
atom.config.set('editor.softWrap', true)
atom.config.set('editor.softWrapHangingIndent', 2)
expect(editor.lineTextForScreenRow(1)).toEqual ' 9'
atom.config.set('editor.softWrapHangingIndent', 4)
expect(editor.lineTextForScreenRow(1)).toEqual ' 9'
describe "::getElement", ->
it "returns an element", ->
expect(editor.getElement() instanceof HTMLElement).toBe(true)

View File

@@ -0,0 +1,29 @@
TitleBar = require '../src/title-bar'
describe "TitleBar", ->
it "updates the title based on document.title when the active pane item changes", ->
titleBar = new TitleBar({
workspace: atom.workspace,
themes: atom.themes,
applicationDelegate: atom.applicationDelegate,
})
expect(titleBar.element.querySelector('.title').textContent).toBe document.title
initialTitle = document.title
atom.workspace.getActivePane().activateItem({
getTitle: -> 'Test Title'
})
expect(document.title).not.toBe(initialTitle)
expect(titleBar.element.querySelector('.title').textContent).toBe document.title
it "can update the sheet offset for the current window based on its height", ->
titleBar = new TitleBar({
workspace: atom.workspace,
themes: atom.themes,
applicationDelegate: atom.applicationDelegate,
})
expect(->
titleBar.updateWindowSheetOffset()
).not.toThrow()

View File

@@ -206,6 +206,7 @@ describe "WindowEventHandler", ->
webContentsSpy = jasmine.createSpyObj("webContents", ["copy", "paste"])
spyOn(atom.applicationDelegate, "getCurrentWindow").andReturn({
webContents: webContentsSpy
on: ->
})
nativeKeyBindingsInput = document.createElement("input")

View File

@@ -31,6 +31,7 @@ ContextMenuManager = require './context-menu-manager'
CommandInstaller = require './command-installer'
Clipboard = require './clipboard'
Project = require './project'
TitleBar = require './title-bar'
Workspace = require './workspace'
PanelContainer = require './panel-container'
Panel = require './panel'
@@ -196,6 +197,7 @@ class AtomEnvironment extends Model
notificationManager: @notifications, @applicationDelegate, @clipboard, viewRegistry: @views, assert: @assert.bind(this),
textEditorRegistry: @textEditors,
})
@themes.workspace = @workspace
@autoUpdater = new AutoUpdateManager({@applicationDelegate})
@@ -554,10 +556,6 @@ class AtomEnvironment extends Model
# Extended: Set the full screen state of the current window.
setFullScreen: (fullScreen=false) ->
@applicationDelegate.setWindowFullScreen(fullScreen)
if fullScreen
@document.body.classList.add("fullscreen")
else
@document.body.classList.remove("fullscreen")
# Extended: Toggle the full screen state of the current window.
toggleFullScreen: ->
@@ -683,6 +681,9 @@ class AtomEnvironment extends Model
@deserialize(state) if state?
@deserializeTimings.atom = Date.now() - startTime
if process.platform is 'darwin' and @config.get('core.useCustomTitleBar')
@workspace.addHeaderPanel({item: new TitleBar({@workspace, @themes, @applicationDelegate})})
@document.body.appendChild(@views.getView(@workspace))
@backgroundStylesheet?.remove()

View File

@@ -261,3 +261,9 @@ if process.platform in ['win32', 'linux']
type: 'boolean'
default: false
description: 'Automatically hide the menu bar and toggle it by pressing Alt. This is only supported on Windows & Linux.'
if process.platform is 'darwin'
module.exports.core.properties.useCustomTitleBar =
type: 'boolean'
default: false
description: 'Use custom, theme-aware title-bar.<br />Note: Note: This currently does not include a proxy icon.<br />This setting will require a relaunch of Atom to take effect.'

View File

@@ -144,7 +144,7 @@ class DecorationManager extends Model
else
delete @overlayDecorationsById[decoration.id]
didDestroyDecoration: (decoration) ->
didDestroyMarkerDecoration: (decoration) ->
{marker} = decoration
return unless decorations = @decorationsByMarkerId[marker.id]
index = decorations.indexOf(decoration)

View File

@@ -69,16 +69,16 @@ class Decoration
@destroyed = false
@markerDestroyDisposable = @marker.onDidDestroy => @destroy()
# Essential: Destroy this marker.
# Essential: Destroy this marker decoration.
#
# If you own the marker, you should use {DisplayMarker::destroy} which will destroy
# this decoration.
# You can also destroy the marker if you own it, which will destroy this
# decoration.
destroy: ->
return if @destroyed
@markerDestroyDisposable.dispose()
@markerDestroyDisposable = null
@destroyed = true
@decorationManager.didDestroyDecoration(this)
@decorationManager.didDestroyMarkerDecoration(this)
@emitter.emit 'did-destroy'
@emitter.dispose()

View File

@@ -1,116 +0,0 @@
'use babel'
import {spawnSync} from 'child_process'
import os from 'os'
// Gets a dump of the user's configured shell environment.
//
// Returns the output of the `env` command or `undefined` if there was an error.
function getRawShellEnv () {
let shell = getUserShell()
// The `-ilc` set of options was tested to work with the macOS v10.11
// default-installed versions of bash, zsh, sh, and ksh. It *does not*
// work with csh or tcsh.
let results = spawnSync(shell, ['-ilc', 'env'], {encoding: 'utf8'})
if (results.error || !results.stdout || results.stdout.length <= 0) {
return
}
return results.stdout
}
function getUserShell () {
if (process.env.SHELL) {
return process.env.SHELL
}
return '/bin/bash'
}
// Gets the user's configured shell environment.
//
// Returns a copy of the user's shell enviroment.
function getFromShell () {
let shellEnvText = getRawShellEnv()
if (!shellEnvText) {
return
}
let env = {}
for (let line of shellEnvText.split(os.EOL)) {
if (line.includes('=')) {
let components = line.split('=')
if (components.length === 2) {
env[components[0]] = components[1]
} else {
let k = components.shift()
let v = components.join('=')
env[k] = v
}
}
}
return env
}
function needsPatching (options = { platform: process.platform, env: process.env }) {
if (options.platform === 'darwin' && !options.env.PWD) {
let shell = getUserShell()
if (shell.endsWith('csh') || shell.endsWith('tcsh') || shell.endsWith('fish')) {
return false
}
return true
}
return false
}
// Fix for #11302 because `process.env` on Windows is a magic object that offers case-insensitive
// environment variable matching. By always cloning to `process.env` we prevent breaking the
// underlying functionality.
function clone (to, from) {
for (var key in to) {
// Don't erase NODE_ENV. Fixes #12024
if (key !== 'NODE_ENV') {
delete to[key]
}
}
Object.assign(to, from)
}
function normalize (options = {}) {
if (options && options.env) {
clone(process.env, options.env)
}
if (!options.env) {
options.env = process.env
}
if (!options.platform) {
options.platform = process.platform
}
if (needsPatching(options)) {
// Patch the `process.env` on startup to fix the problem first documented
// in #4126. Retain the original in case someone needs it.
let shellEnv = getFromShell()
if (shellEnv && shellEnv.PATH) {
process._originalEnv = Object.assign({}, process.env)
clone(process.env, shellEnv)
}
}
}
function replace (env) {
if (!env || !env.PATH) {
return
}
clone(process.env, env)
}
export default { getFromShell, needsPatching, normalize, replace }

View File

@@ -1,15 +1,13 @@
# Like sands through the hourglass, so are the days of our lives.
module.exports = ({blobStore}) ->
environmentHelpers = require('./environment-helpers')
updateProcessEnv = require('./update-process-env')
path = require 'path'
require './window'
{getWindowLoadSettings} = require './window-load-settings-helpers'
{ipcRenderer} = require 'electron'
{resourcePath, isSpec, devMode, env} = getWindowLoadSettings()
# Set baseline environment
environmentHelpers.normalize({env: env})
env = process.env
updateProcessEnv(env)
# Add application-specific exports to module search path.
exportsPath = path.join(resourcePath, 'exports')
@@ -37,5 +35,5 @@ module.exports = ({blobStore}) ->
setTimeout (-> document.querySelector('atom-workspace').focus()), 0
window.addEventListener('focus', windowFocused)
ipcRenderer.on('environment', (event, env) ->
environmentHelpers.replace(env)
updateProcessEnv(env)
)

View File

@@ -76,6 +76,8 @@ class AtomApplication
@config.setSchema null, {type: 'object', properties: _.clone(require('../config-schema'))}
@config.load()
@config.onDidChange 'core.useCustomTitleBar', @promptForRelaunch
@autoUpdateManager = new AutoUpdateManager(@version, options.test, @resourcePath, @config)
@applicationMenu = new ApplicationMenu(@version, @autoUpdateManager)
@atomProtocolHandler = new AtomProtocolHandler(@resourcePath, @safeMode)
@@ -87,6 +89,7 @@ class AtomApplication
@setupDockMenu()
@storageFolder = new StorageFolder(process.env.ATOM_HOME)
if options.pathsToOpen?.length > 0 or options.urlsToOpen?.length > 0 or options.test
@openWithOptions(options)
else
@@ -706,3 +709,15 @@ class AtomApplication
openOptions.defaultPath = path
dialog.showOpenDialog(parentWindow, openOptions, callback)
promptForRelaunch: ->
chosen = dialog.showMessageBox BrowserWindow.getFocusedWindow(),
type: 'warning'
title: 'Relaunch required'
message: "You will need to relaunch Atom for this change to take effect."
buttons: ['Quit Atom', 'Cancel']
if chosen is 0
# once we're using electron v.1.2.2
# app.relaunch()
app.quit()

View File

@@ -40,6 +40,9 @@ class AtomWindow
if process.platform is 'linux'
options.icon = @constructor.iconPath
if @shouldHideTitleBar()
options.titleBarStyle = 'hidden'
@browserWindow = new BrowserWindow options
global.atomApplication.addWindow(this)
@@ -199,6 +202,11 @@ class AtomWindow
[width, height] = @browserWindow.getSize()
{x, y, width, height}
shouldHideTitleBar: ->
not @isSpec and
process.platform is 'darwin' and
global.atomApplication.config.get('core.useCustomTitleBar')
close: -> @browserWindow.close()
focus: -> @browserWindow.focus()

View File

@@ -113,9 +113,11 @@ function setupAtomHome ({setPortable}) {
try {
atomHome = fs.realpathSync(atomHome)
} finally {
process.env.ATOM_HOME = atomHome
} catch (e) {
// Don't throw an error if atomHome doesn't exist.
}
process.env.ATOM_HOME = atomHome
}
function setupCompileCache () {

View File

@@ -245,7 +245,8 @@ class TextEditor extends Model
tabLength: @getTabLength(),
ratioForCharacter: @ratioForCharacter.bind(this),
isWrapBoundary: isWrapBoundary,
foldCharacter: ZERO_WIDTH_NBSP
foldCharacter: ZERO_WIDTH_NBSP,
softWrapHangingIndent: @config.get('editor.softWrapHangingIndent', scope: @getRootScopeDescriptor())
})
destroyed: ->

21
src/title-bar.coffee Normal file
View File

@@ -0,0 +1,21 @@
module.exports =
class TitleBar
constructor: ({@workspace, @themes, @applicationDelegate}) ->
@element = document.createElement('div')
@element.classList.add('title-bar')
@titleElement = document.createElement('div')
@titleElement.classList.add('title')
@element.appendChild(@titleElement)
@workspace.onDidChangeActivePaneItem => @updateTitle()
@themes.onDidChangeActiveThemes => @updateWindowSheetOffset()
@updateTitle()
@updateWindowSheetOffset()
updateTitle: ->
@titleElement.textContent = document.title
updateWindowSheetOffset: ->
@applicationDelegate.getCurrentWindow().setSheetOffset(@element.offsetHeight)

49
src/update-process-env.js Normal file
View File

@@ -0,0 +1,49 @@
/** @babel */
import {spawnSync} from 'child_process'
const ENVIRONMENT_VARIABLES_TO_PRESERVE = new Set(['NODE_ENV', 'NODE_PATH'])
export default function updateProcessEnv (launchEnv) {
let envToAssign
if (launchEnv && launchEnv.PWD) {
envToAssign = launchEnv
} else {
if (process.platform === 'darwin') {
envToAssign = getEnvFromShell()
}
}
if (envToAssign) {
for (let key in process.env) {
if (!ENVIRONMENT_VARIABLES_TO_PRESERVE.has(key)) {
delete process.env[key]
}
}
for (let key in envToAssign) {
if (!ENVIRONMENT_VARIABLES_TO_PRESERVE.has(key)) {
process.env[key] = envToAssign[key]
}
}
}
}
function getEnvFromShell () {
let shell = process.env.SHELL
if (shell && (shell.endsWith('/bash') || shell.endsWith('/sh'))) {
let {stdout} = spawnSync(shell, ['-ilc', 'env'], {encoding: 'utf8'})
if (stdout) {
let result = {}
for (let line of stdout.split('\n')) {
if (line.includes('=')) {
let components = line.split('=')
let key = components.shift()
let value = components.join('=')
result[key] = value
}
}
return result
}
}
}

View File

@@ -23,6 +23,15 @@ class WindowEventHandler
@subscriptions.add listen(@document, 'click', 'a', @handleLinkClick)
@subscriptions.add listen(@document, 'submit', 'form', @handleFormSubmit)
browserWindow = @applicationDelegate.getCurrentWindow()
browserWindow.on 'enter-full-screen', @handleEnterFullScreen
@subscriptions.add new Disposable =>
browserWindow.removeListener('enter-full-screen', @handleEnterFullScreen)
browserWindow.on 'leave-full-screen', @handleLeaveFullScreen
@subscriptions.add new Disposable =>
browserWindow.removeListener('leave-full-screen', @handleLeaveFullScreen)
@subscriptions.add @atomEnvironment.commands.add @window,
'window:toggle-full-screen': @handleWindowToggleFullScreen
'window:close': @handleWindowClose
@@ -136,6 +145,12 @@ class WindowEventHandler
@document.body.classList.add('is-blurred')
@atomEnvironment.storeWindowDimensions()
handleEnterFullScreen: =>
@document.body.classList.add("fullscreen")
handleLeaveFullScreen: =>
@document.body.classList.remove("fullscreen")
handleWindowBeforeunload: =>
confirmed = @atomEnvironment.workspace?.confirmClose(windowCloseRequested: true)
if confirmed and not @reloadRequested and not @atomEnvironment.inSpecMode() and @atomEnvironment.getCurrentWindow().isWebViewFocused()

View File

@@ -21,6 +21,7 @@
@import "panes";
@import "syntax";
@import "text-editor-light";
@import "title-bar";
@import "workspace-view";
// Atom UI library

41
static/title-bar.less Normal file
View File

@@ -0,0 +1,41 @@
@import "ui-variables";
@title-bar-text-size: 13px;
@title-bar-height: 23px;
@title-bar-background-color: @base-background-color;
@title-bar-border-color: @base-border-color;
body.fullscreen .title-bar {
margin-top: -@title-bar-height;
}
.title-bar {
height: @title-bar-height;
transition: margin-top 160ms;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: @title-bar-text-size;
-webkit-user-select: none;
-webkit-app-region: drag;
padding: 0 70px;
overflow: hidden;
.title {
flex: 0 1 auto;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
background-color: @title-bar-background-color;
border-bottom: 1px solid @title-bar-border-color;
.is-blurred & {
color: @text-color-subtle;
}
}

View File

@@ -79,7 +79,6 @@
@tab-height: 30px;
// Other
@font-family: 'BlinkMacSystemFont', 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, sans-serif;