Skip to content

Commit 14b0f86

Browse files
feat: add prettier for snippets formatting (#22)
1 parent 6d14e7d commit 14b0f86

File tree

14 files changed

+159
-15
lines changed

14 files changed

+159
-15
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"@types/markdown-it": "^12.2.3",
6565
"@types/markdown-it-link-attributes": "^3.0.1",
6666
"@types/node": "^17.0.4",
67+
"@types/prettier": "^2.6.0",
6768
"@types/sanitize-html": "^2.6.2",
6869
"@types/webpack": "^5.28.0",
6970
"@typescript-eslint/eslint-plugin": "^5.8.0",

src/main/menu/main.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,15 @@ const editorMenu: MenuItemConstructorOptions[] = [
200200
)
201201
}
202202
},
203+
{
204+
label: 'Format',
205+
accelerator: 'Shift+CommandOrControl+F',
206+
click: () => {
207+
BrowserWindow.getFocusedWindow()?.webContents.send(
208+
'main-menu:format-snippet'
209+
)
210+
}
211+
},
203212
{
204213
label: 'Preview Markdown',
205214
accelerator: 'Shift+CommandOrControl+M',

src/main/store/module/preferences.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ export default new Store<PreferencesStore>({
1919
fontFamily: 'SF Mono, Consolas, Menlo',
2020
fontSize: 12,
2121
showInvisibles: false,
22-
tabSize: 2
22+
tabSize: 2,
23+
trailingComma: 'none',
24+
semi: false,
25+
singleQuote: true
2326
}
2427
}
2528
})

src/renderer/App.vue

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ import {
2424
onAddNewSnippet,
2525
onAddNewFragment,
2626
onAddNewFolder,
27-
onCopySnippet
27+
onCopySnippet,
28+
emitter
2829
} from '@/composable'
2930
3031
// По какой то причине необходимо явно установить роут в '/'
@@ -115,12 +116,20 @@ ipc.on('main-menu:preview-markdown', async () => {
115116
ipc.on('main-menu:copy-snippet', () => {
116117
onCopySnippet()
117118
})
119+
120+
ipc.on('main-menu:format-snippet', () => {
121+
emitter.emit('format-snippet', true)
122+
})
118123
</script>
119124

120125
<style lang="scss">
121126
body {
122127
margin: 0;
123128
}
129+
#app {
130+
height: 100vh;
131+
overflow: hidden;
132+
}
124133
.app {
125134
&-title-bar {
126135
position: absolute;

src/renderer/components/editor/TheEditor.vue

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ import { languages } from './languages'
3737
import { useAppStore } from '@/store/app'
3838
import { useSnippetStore } from '@/store/snippets'
3939
import { track } from '@/electron'
40+
import prettier from 'prettier/standalone'
41+
import parserTypescript from 'prettier/parser-typescript'
42+
import parserBabel from 'prettier/parser-babel'
43+
import parserHtml from 'prettier/parser-html'
44+
import parserGraphql from 'prettier/parser-graphql'
45+
import parserMarkdown from 'prettier/parser-markdown'
46+
import parserPostcss from 'prettier/parser-postcss'
47+
import parserYaml from 'prettier/parser-yaml'
48+
import { emitter } from '@/composable'
4049
4150
interface Props {
4251
lang: Language
@@ -148,6 +157,54 @@ const setValue = () => {
148157
}
149158
}
150159
160+
const format = () => {
161+
const availableLang: Language[] = [
162+
'javascript',
163+
'typescript',
164+
'json',
165+
'json5',
166+
'yaml',
167+
'html',
168+
'markdown',
169+
'graphqlschema',
170+
'css',
171+
'sass',
172+
'scss',
173+
'less'
174+
]
175+
176+
if (!availableLang.includes(props.lang)) return
177+
178+
let parser = props.lang as string
179+
180+
if (props.lang === 'javascript') parser = 'babel'
181+
if (props.lang === 'graphqlschema') parser = 'graphql'
182+
183+
try {
184+
const formatted = prettier.format(props.modelValue, {
185+
parser,
186+
plugins: [
187+
parserTypescript,
188+
parserBabel,
189+
parserHtml,
190+
parserMarkdown,
191+
parserPostcss,
192+
parserGraphql,
193+
parserYaml
194+
],
195+
tabWidth: appStore.editor.tabSize,
196+
trailingComma: appStore.editor.trailingComma,
197+
semi: appStore.editor.semi,
198+
singleQuote: appStore.editor.singleQuote
199+
})
200+
201+
// Обновляем напрямую без debounce
202+
snippetStore.patchCurrentSnippetContentByKey('value', formatted)
203+
} catch (err) {
204+
console.error(err)
205+
}
206+
}
207+
151208
const setLang = () => {
152209
editor.session.setMode(`ace/mode/${localLang.value}`)
153210
track('snippets/set-language', localLang.value)
@@ -213,6 +270,8 @@ watch(
213270
}
214271
)
215272
273+
emitter.on('format-snippet', () => format())
274+
216275
window.addEventListener('resize', () => {
217276
forceRefresh.value = Math.random()
218277
})

src/renderer/components/preferences/EditorPreferences.vue

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<template>
22
<div class="editor-preferences">
33
<AppForm>
4+
<h4>Editor</h4>
45
<AppFormItem label="Font Size">
56
<AppInput
67
v-model="appStore.editor.fontSize"
@@ -30,6 +31,25 @@
3031
name="showInvisibles"
3132
/>
3233
</AppFormItem>
34+
<h4>Prettier</h4>
35+
<AppFormItem label="Trailing Comma">
36+
<AppSelect
37+
v-model="appStore.editor.trailingComma"
38+
:options="trailingCommaOptions"
39+
/>
40+
</AppFormItem>
41+
<AppFormItem label="Semi">
42+
<AppCheckbox
43+
v-model="appStore.editor.semi"
44+
name="semi"
45+
/>
46+
</AppFormItem>
47+
<AppFormItem label="Single Quote">
48+
<AppCheckbox
49+
v-model="appStore.editor.singleQuote"
50+
name="semi"
51+
/>
52+
</AppFormItem>
3353
</AppForm>
3454
</div>
3555
</template>
@@ -46,6 +66,12 @@ const wrapOptions = [
4666
{ label: 'Off', value: 'off' }
4767
]
4868
69+
const trailingCommaOptions = [
70+
{ label: 'None', value: 'none' },
71+
{ label: 'All', value: 'all' },
72+
{ label: 'ES6', value: 'es6' }
73+
]
74+
4975
watch(
5076
() => appStore.editor,
5177
v => {
@@ -55,4 +81,11 @@ watch(
5581
)
5682
</script>
5783

58-
<style lang="scss" scoped></style>
84+
<style lang="scss" scoped>
85+
h4 {
86+
&:first-child {
87+
margin-top: 0;
88+
}
89+
margin-bottom: 0;
90+
}
91+
</style>

src/renderer/components/ui/menu/AppMenu.vue

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@
1111
{{ i.name }}
1212
</div>
1313
</div>
14-
<div class="body">
15-
<slot />
14+
<div
15+
ref="bodyRef"
16+
class="body"
17+
>
18+
<PerfectScrollbar>
19+
<slot />
20+
</PerfectScrollbar>
1621
</div>
1722
</div>
1823
</template>
@@ -39,9 +44,12 @@ const props = defineProps<Props>()
3944
4045
const items = ref<Item[]>([])
4146
const value = computed(() => props.modelValue)
47+
const bodyRef = ref<HTMLElement>()
4248
4349
const onClickItem = (item: Item) => {
4450
emit('update:modelValue', item.value)
51+
const el = bodyRef.value?.querySelector('.ps')
52+
if (el) el.scrollTop = 0
4553
}
4654
4755
const update = (value: string) => {
@@ -55,15 +63,22 @@ provide('items', items.value)
5563

5664
<style lang="scss" scoped>
5765
.menu {
66+
width: 100%;
67+
height: 300px;
5868
display: grid;
5969
grid-template-columns: 150px 1fr;
6070
gap: var(--spacing-sm);
61-
}
62-
.name {
63-
padding: var(--spacing-xs);
64-
&.is-selected {
65-
border-radius: 5px;
66-
background-color: var(--color-contrast-lower-alt);
71+
.name {
72+
padding: var(--spacing-xs);
73+
&.is-selected {
74+
border-radius: 5px;
75+
background-color: var(--color-contrast-lower-alt);
76+
}
77+
}
78+
.body {
79+
:deep(.ps) {
80+
height: calc(100vh - 80px);
81+
}
6782
}
6883
}
6984
</style>

src/renderer/store/app.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ const EDITOR_DEFAULTS: EditorSettings = {
88
fontSize: 12,
99
showInvisibles: false,
1010
tabSize: 2,
11-
wrap: 'free'
11+
wrap: 'free',
12+
trailingComma: 'none',
13+
semi: false,
14+
singleQuote: true
1215
}
1316

1417
export const useAppStore = defineStore('app', {

src/renderer/views/Preferences.vue

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,15 @@ track('preferences')
4545
margin: 0;
4646
}
4747
margin-top: var(--title-bar-height);
48-
padding: var(--spacing-sm);
4948
}
5049
.title {
50+
padding: var(--spacing-sm);
5151
display: flex;
5252
align-items: center;
5353
justify-content: space-between;
5454
}
5555
.body {
56-
padding-top: var(--spacing-sm);
56+
padding: 0 0 var(--spacing-sm) var(--spacing-sm);
5757
display: grid;
58-
grid-template-columns: 200px 1fr;
5958
}
6059
</style>

src/shared/types/main/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type MainMenuAction =
3333
| 'preferences'
3434
| 'new-snippet'
3535
| 'copy-snippet'
36+
| 'format-snippet'
3637
| 'new-fragment'
3738
| 'new-folder'
3839
| 'search'

0 commit comments

Comments
 (0)