This repository has been archived by the owner on Apr 1, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 298
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add initial implementation of prettier plugin * add config options to test using config functionality * update config to allow disabling, add status icon * comment out console.log add check if code is formatted add initial attempt at cursor position * fix config to camelcase * add assets for prettier icon * add line column and [wip] attempt to return correct cursor pos * fix cursor positioning * Remove linecolumn, not working remove prettier asset more work on cursor positioning add success and error status icons * update yarn lock * Fix eslintrc add allowedFiletypes checking * add onClick fn to prettier element add allowedFiletypes option to config * remove console.logs * add convert offset function and get cursor offset function * use vim based byte offset or prettier * remove unused dependencies * add install command or prettier plugin * add install command to plugins command * update dir or prettier plugin * relocate prettier plugin to correct dir * add filepath for parser inference and change icon * remove extra CR added on joining string * add printWidth option and add graphql to default fts * fix print width use number * add editor config option add buffer state to track if modified add icon colors * remove console.log * conditionally render prettier status item * minor change to rerun tests * [WIP] Add prettier-plugin test * [WIP] comment out test while attempting to test prettier plugin\ * comment out non-functional tests * re-add commented tests, deactivate prettier test * Tweak prettier plugin architecture for tests * comment out ci tests and contiue work on prettier test * fix config for test, update test [WIP] * add functioning ci test for prettier * ensure existence of prettier status item * add helper functions to common add new [wip] ci test * refactor get cursor offset to a get method make convertCursorPos zero base to march getCursorPos * add new bufferCursorTest file * fix missing CI test and remove redundant calc * remove redundant methods from prettier test * tweak function to keep state within function rather than globally move failing windows test to bottom to see if only that test fails * remove specific use of newline per platform * switch to a more functional approach slightly excessive for now but a foundation for further tweaks in the ongoing development of this plugin * fix prettier callback to use new state tracking version switch to function keyword to ensure applyprettier is hoisted so callback can reference it * fix typo and add check in prettier rc function * use prettier info to poplulate compatible filetypes * fix incorrect ref to config * actually remove incorrect conffig ref
- Loading branch information
Showing
13 changed files
with
465 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
{ | ||
"rules": { | ||
"indent": 0, | ||
"linebreak-style": ["off", "unix"], | ||
"quotes": ["error", "double", { "allowTemplateLiterals": true }], | ||
"semi": ["error", "never"], | ||
"array-callback-return": "error", | ||
"eqeqeq": "error", | ||
"no-console": "on", | ||
"strict": 0, | ||
"no-unused-vars": 0, | ||
"no-undef": 1, | ||
"no-undefined": 1, | ||
"camelcase": 1, | ||
"no-underscore-dangle": 0, | ||
"no-console": 0, | ||
"no-invalid-this": 1, | ||
"no-useless-return": 1, | ||
"comma-dangle": ["error", "only-multiline"], | ||
"comma-spacing": ["error", { "before": false, "after": true }] | ||
}, | ||
"env": { | ||
"es6": true, | ||
"browser": true, | ||
"jasmine": true, | ||
"mocha": true | ||
}, | ||
"settings": { | ||
"ecmascript": 6, | ||
"jsx": true | ||
}, | ||
"extends": "eslint:recommended", | ||
"parser": "babel-eslint", | ||
"plugins": ["react"], | ||
"globals": { | ||
"_": false, | ||
"remote": false, | ||
"process": false, | ||
"module": false, | ||
"require": false, | ||
"__dirname": false, | ||
"preloadedData": false | ||
}, | ||
"root": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
const path = require("path") | ||
const prettier = require("prettier") | ||
|
||
// Helper functions | ||
const compose = (...fns) => argument => fns.reduceRight((arg, fn) => fn(arg), argument) | ||
const joinOrSplit = (method, by = "\n") => array => array[method](by) | ||
const join = joinOrSplit("join") | ||
const split = joinOrSplit("split") | ||
const isEqual = toCompare => initialItem => initialItem === toCompare | ||
const isTrue = (...args) => args.every(a => Boolean(a)) | ||
const eitherOr = (...args) => args.find(a => !!a) | ||
const flatten = multidimensional => [].concat(...multidimensional) | ||
|
||
const isCompatible = (allowedFiletypes, defaultFiletypes) => filePath => { | ||
const filetypes = isTrue(allowedFiletypes, Array.isArray(allowedFiletypes)) | ||
? allowedFiletypes | ||
: defaultFiletypes | ||
const extension = path.extname(filePath) | ||
return filetypes.includes(extension) | ||
} | ||
|
||
const getSupportedLanguages = async () => { | ||
const info = await prettier.getSupportInfo() | ||
return flatten(info.languages.map(lang => lang.extensions)) | ||
} | ||
|
||
const activate = async Oni => { | ||
const config = Oni.configuration.getValue("oni.plugins.prettier") | ||
const prettierItem = Oni.statusBar.createItem(0, "oni.plugins.prettier") | ||
|
||
const applyPrettierWithState = applyPrettier() | ||
const defaultFiletypes = await getSupportedLanguages() | ||
|
||
const callback = async () => { | ||
const isNormalMode = Oni.editors.activeEditor.mode === "normal" | ||
if (isNormalMode) { | ||
await applyPrettierWithState(Oni) | ||
} | ||
} | ||
Oni.commands.registerCommand({ | ||
command: "autoformat.prettier", | ||
name: "Autoformat with Prettier", | ||
execute: callback, | ||
}) | ||
|
||
const checkPrettierrc = async bufferPath => { | ||
if (!bufferPath) { | ||
throw new Error(`No buffer path passed for prettier to check for a Prettierrc`) | ||
} | ||
try { | ||
return await prettier.resolveConfig(bufferPath) | ||
} catch (e) { | ||
throw new Error(`Error parsing config file, ${e}`) | ||
} | ||
} | ||
|
||
// Status Bar Component ---- | ||
const { errorElement, successElement, prettierElement } = createPrettierComponent(Oni, callback) | ||
|
||
prettierItem.setContents(prettierElement) | ||
|
||
const setStatusBarContents = (statusBarItem, defaultElement) => async ( | ||
statusElement, | ||
timeOut = 3500, | ||
) => { | ||
statusBarItem.setContents(statusElement) | ||
await setTimeout(() => statusBarItem.setContents(defaultElement), timeOut) | ||
} | ||
|
||
const setPrettierStatus = setStatusBarContents(prettierItem, prettierElement) | ||
|
||
function applyPrettier() { | ||
// Track the buffer state within the function using a closure | ||
// if the buffer as a string is the same as the last state | ||
// do no format because nothing has changed | ||
let lastBufferState = null | ||
|
||
// pass in Oni explicitly - Make dependencies clearer | ||
return async Oni => { | ||
const { activeBuffer } = Oni.editors.activeEditor | ||
|
||
const [arrayOfLines, { line, character }] = await Promise.all([ | ||
activeBuffer.getLines(), | ||
activeBuffer.getCursorPosition(), | ||
]) | ||
|
||
const hasNotChanged = compose(isEqual(lastBufferState), join) | ||
|
||
if (hasNotChanged(arrayOfLines)) { | ||
return | ||
} | ||
|
||
try { | ||
const prettierrc = await checkPrettierrc(activeBuffer.filePath) | ||
const prettierConfig = eitherOr(prettierrc, config.settings) | ||
|
||
// Pass in the file path so prettier can infer the correct parser to use | ||
const { formatted, cursorOffset } = prettier.formatWithCursor( | ||
join(arrayOfLines), | ||
Object.assign({ filepath: activeBuffer.filePath }, prettierConfig, { | ||
cursorOffset: activeBuffer.cursorOffset, | ||
}), | ||
) | ||
if (!formatted) { | ||
throw new Error("Couldn't format the buffer") | ||
} | ||
|
||
await setPrettierStatus(successElement) | ||
|
||
const withoutFinalCR = formatted.replace(/\n$/, "") | ||
lastBufferState = withoutFinalCR | ||
|
||
const [, { character, line }] = await Promise.all([ | ||
activeBuffer.setLines(0, arrayOfLines.length, split(withoutFinalCR)), | ||
activeBuffer.convertOffsetToLineColumn(cursorOffset), | ||
]) | ||
|
||
await activeBuffer.setCursorPosition(line, character) | ||
await Oni.editors.activeEditor.neovim.command("w") | ||
} catch (e) { | ||
console.warn(`Couldn't format the buffer because: ${e}`) | ||
await setPrettierStatus(errorElement) | ||
} | ||
} | ||
} | ||
|
||
const { allowedFiletypes, formatOnSave, enabled } = config | ||
const checkCompatibility = isCompatible(allowedFiletypes, defaultFiletypes) | ||
|
||
Oni.editors.activeEditor.onBufferEnter.subscribe(({ filePath }) => { | ||
const hasCompatibility = checkCompatibility(filePath) | ||
|
||
hasCompatibility ? prettierItem.show() : prettierItem.hide() | ||
}) | ||
|
||
Oni.editors.activeEditor.onBufferSaved.subscribe(async ({ filePath }) => { | ||
const hasCompatibility = checkCompatibility(filePath) | ||
|
||
const canApplyPrettier = isTrue(formatOnSave, enabled, hasCompatibility) | ||
if (canApplyPrettier) { | ||
await applyPrettierWithState(Oni) | ||
} | ||
}) | ||
return { applyPrettier: applyPrettierWithState, checkCompatibility, checkPrettierrc } | ||
} | ||
|
||
function createPrettierComponent(Oni, onClick) { | ||
const { React } = Oni.dependencies | ||
|
||
const background = Oni.colors.getColor("highlight.mode.normal.background") | ||
const foreground = Oni.colors.getColor("highlight.mode.normal.foreground") | ||
const style = { | ||
width: "100%", | ||
height: "100%", | ||
display: "flex", | ||
alignItems: "center", | ||
justifyContent: "center", | ||
paddingLeft: "8px", | ||
paddingRight: "8px", | ||
color: "white", | ||
backgroundColor: foreground, | ||
} | ||
|
||
const prettierIcon = (type = "magic") => | ||
Oni.ui.createIcon({ | ||
name: type, | ||
size: Oni.ui.iconSize.Default, | ||
}) | ||
|
||
const iconContainer = (type, color = "white") => | ||
React.createElement("div", { style: { padding: "0 6px 0 0", color } }, prettierIcon(type)) | ||
|
||
const prettierElement = React.createElement( | ||
"div", | ||
{ className: "prettier", style, onClick }, | ||
iconContainer(), | ||
"prettier", | ||
) | ||
|
||
const errorElement = React.createElement( | ||
"div", | ||
{ style, className: "prettier" }, | ||
iconContainer("exclamation-triangle", "yellow"), | ||
"prettier", | ||
) | ||
|
||
const successElement = React.createElement( | ||
"div", | ||
{ style, className: "prettier" }, | ||
iconContainer("check", "#5AB379"), | ||
"prettier", | ||
) | ||
|
||
return { | ||
errorElement, | ||
prettierElement, | ||
successElement, | ||
} | ||
} | ||
|
||
module.exports = { activate } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"name": "oni-plugin-prettier", | ||
"version": "1.0.0", | ||
"main": "index.js", | ||
"engines": { | ||
"oni": "^0.2.6" | ||
}, | ||
"scripts": {}, | ||
"oni": { | ||
"supportedFileTypes": [ | ||
"*" | ||
] | ||
}, | ||
"dependencies": { | ||
"prettier": "^1.11.1" | ||
}, | ||
"devDependencies": {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.