Skip to content

Commit b7e9b7b

Browse files
committed
initial copy
1 parent 5e55219 commit b7e9b7b

File tree

8 files changed

+932
-0
lines changed

8 files changed

+932
-0
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/**
2+
* Copyright (c) 2017-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
* @flow
10+
* @format
11+
* @emails oncall+nuclide
12+
*/
13+
import {Range} from 'atom';
14+
import {observeTextEditors} from 'nuclide-commons-atom/FileEventHandlers';
15+
import {SAVE_TIMEOUT} from '../lib/CodeFormatManager';
16+
import UniversalDisposable from 'nuclide-commons/UniversalDisposable';
17+
import temp from 'temp';
18+
import * as config from '../lib/config';
19+
import CodeFormatManager from '../lib/CodeFormatManager';
20+
import waitsFor from '../../../../../jest/waits_for';
21+
22+
const sleep = n => new Promise(r => setTimeout(r, n));
23+
24+
describe('CodeFormatManager', () => {
25+
let textEditor;
26+
let manager;
27+
let disposables;
28+
beforeEach(async () => {
29+
manager = new CodeFormatManager();
30+
disposables = new UniversalDisposable(observeTextEditors());
31+
temp.track();
32+
const file = temp.openSync();
33+
textEditor = await atom.workspace.open(file.path);
34+
});
35+
36+
afterEach(async () => {
37+
manager.dispose();
38+
disposables.dispose();
39+
});
40+
41+
it('formats an editor on request', async () => {
42+
manager.addRangeProvider({
43+
grammarScopes: ['text.plain.null-grammar'],
44+
priority: 1,
45+
formatCode: () =>
46+
Promise.resolve([
47+
{
48+
oldRange: new Range([0, 0], [0, 3]),
49+
oldText: 'abc',
50+
newText: 'def',
51+
},
52+
]),
53+
});
54+
55+
textEditor.setText('abc');
56+
atom.commands.dispatch(
57+
atom.views.getView(textEditor),
58+
'code-format:format-code',
59+
);
60+
await waitsFor(() => textEditor.getText() === 'def');
61+
});
62+
63+
it('format an editor using formatEntireFile', async () => {
64+
manager.addFileProvider({
65+
grammarScopes: ['text.plain.null-grammar'],
66+
priority: 1,
67+
formatEntireFile: () => Promise.resolve({formatted: 'ghi'}),
68+
});
69+
70+
textEditor.setText('abc');
71+
atom.commands.dispatch(
72+
atom.views.getView(textEditor),
73+
'code-format:format-code',
74+
);
75+
await waitsFor(() => textEditor.getText() === 'ghi');
76+
});
77+
78+
it('formats an editor on type', async () => {
79+
jest.spyOn(config, 'getFormatOnType').mockReturnValue(true);
80+
const provider = {
81+
grammarScopes: ['text.plain.null-grammar'],
82+
priority: 1,
83+
formatAtPosition: () =>
84+
Promise.resolve([
85+
{
86+
oldRange: new Range([0, 0], [0, 3]),
87+
oldText: 'abc',
88+
newText: 'def',
89+
},
90+
]),
91+
keepCursorPosition: false,
92+
};
93+
const spy = jest.spyOn(provider, 'formatAtPosition');
94+
manager.addOnTypeProvider(provider);
95+
96+
textEditor.setText('a');
97+
textEditor.setCursorBufferPosition([0, 1]);
98+
textEditor.insertText('b');
99+
textEditor.insertText('c');
100+
101+
await waitsFor(() => textEditor.getText() === 'def');
102+
// Debouncing should ensure only one format call.
103+
expect(spy.mock.calls.length).toBe(1);
104+
});
105+
106+
it('formats an editor on save', async () => {
107+
jest.spyOn(config, 'getFormatOnSave').mockReturnValue(true);
108+
manager.addOnSaveProvider({
109+
grammarScopes: ['text.plain.null-grammar'],
110+
priority: 1,
111+
formatOnSave: () =>
112+
Promise.resolve([
113+
{
114+
oldRange: new Range([0, 0], [0, 3]),
115+
oldText: 'abc',
116+
newText: 'def',
117+
},
118+
]),
119+
});
120+
121+
textEditor.setText('abc');
122+
await textEditor.save();
123+
expect(textEditor.getText()).toBe('def');
124+
});
125+
126+
it('should still save on timeout', async () => {
127+
jest.spyOn(config, 'getFormatOnSave').mockReturnValue(true);
128+
manager.addRangeProvider({
129+
grammarScopes: ['text.plain.null-grammar'],
130+
priority: 1,
131+
formatCode: async () => {
132+
await sleep(SAVE_TIMEOUT + 1000);
133+
return [];
134+
},
135+
});
136+
137+
const spy = jest.spyOn(textEditor.getBuffer(), 'save');
138+
textEditor.save();
139+
140+
// Wait until the buffer has been saved and verify it has been saved exactly
141+
// once.
142+
await waitsFor(() => spy.mock.calls.length > 0);
143+
expect(spy.mock.calls.length).toBe(1);
144+
});
145+
});

keymaps/code-format.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
".platform-darwin atom-workspace atom-text-editor:not(.mini)": {
3+
"cmd-shift-c": "code-format:format-code"
4+
},
5+
".platform-win32 atom-workspace atom-text-editor:not(.mini)": {
6+
"ctrl-shift-c": "code-format:format-code"
7+
},
8+
".platform-linux atom-workspace atom-text-editor:not(.mini)": {
9+
"ctrl-shift-c": "code-format:format-code"
10+
}
11+
}

0 commit comments

Comments
 (0)