Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions crates-tauri/yaak-app/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -843,8 +843,10 @@ async fn cmd_send_ephemeral_request<R: Runtime>(
}

#[tauri::command]
async fn cmd_format_json(text: &str) -> YaakResult<String> {
Ok(format_json(text, " "))
async fn cmd_format_json(text: &str, indent: Option<u32>) -> YaakResult<String> {
let n = indent.unwrap_or(2);
let indent_str = " ".repeat(n as usize);
Ok(format_json(text, &indent_str))
}

#[tauri::command]
Expand Down
4 changes: 2 additions & 2 deletions crates/yaak-models/bindings/gen_models.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE settings ADD COLUMN editor_indentation INTEGER DEFAULT 2 NOT NULL;
4 changes: 4 additions & 0 deletions crates/yaak-models/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ pub struct Settings {
pub editor_font: Option<String>,
pub editor_font_size: i32,
pub editor_keymap: EditorKeymap,
pub editor_indentation: i32,
pub editor_soft_wrap: bool,
pub hide_window_controls: bool,
// When true (primarily on Windows/Linux), use the native OS window title bar and controls
Expand Down Expand Up @@ -204,6 +205,7 @@ impl UpsertModelInfo for Settings {
(ClientCertificates, client_certificates.into()),
(EditorFontSize, self.editor_font_size.into()),
(EditorKeymap, self.editor_keymap.to_string().into()),
(EditorIndentation, self.editor_indentation.into()),
(EditorSoftWrap, self.editor_soft_wrap.into()),
(EditorFont, self.editor_font.into()),
(InterfaceFont, self.interface_font.into()),
Expand Down Expand Up @@ -232,6 +234,7 @@ impl UpsertModelInfo for Settings {
SettingsIden::ClientCertificates,
SettingsIden::EditorFontSize,
SettingsIden::EditorKeymap,
SettingsIden::EditorIndentation,
SettingsIden::EditorSoftWrap,
SettingsIden::EditorFont,
SettingsIden::InterfaceFontSize,
Expand Down Expand Up @@ -271,6 +274,7 @@ impl UpsertModelInfo for Settings {
editor_font_size: row.get("editor_font_size")?,
editor_font: row.get("editor_font")?,
editor_keymap: EditorKeymap::from_str(editor_keymap.as_str()).unwrap(),
editor_indentation: row.get("editor_indentation")?,
editor_soft_wrap: row.get("editor_soft_wrap")?,
interface_font_size: row.get("interface_font_size")?,
interface_scale: row.get("interface_scale")?,
Expand Down
1 change: 1 addition & 0 deletions crates/yaak-models/src/queries/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ impl<'a> DbContext<'a> {
editor_font_size: 12,
editor_font: None,
editor_keymap: EditorKeymap::Default,
editor_indentation: 2,
editor_soft_wrap: true,
interface_font_size: 14,
interface_scale: 1.0,
Expand Down
14 changes: 14 additions & 0 deletions src-web/components/Settings/SettingsInterface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const keymaps: { value: EditorKeymap; label: string }[] = [
{ value: 'emacs', label: 'Emacs' },
];

const tabIndentOptions = [2, 4, 6, 8, 10].map((n) => ({ label: `${n}`, value: `${n}` }));

export function SettingsInterface() {
const workspace = useAtomValue(activeWorkspaceAtom);
const settings = useAtomValue(settingsAtom);
Expand Down Expand Up @@ -148,6 +150,18 @@ export function SettingsInterface() {
options={keymaps}
onChange={(v) => patchModel(settings, { editorKeymap: v })}
/>
<Select
leftSlot={<Icon icon="arrow_big_right_dash" color="secondary" />}
size="sm"
name="editorIndentation"
label="Editor indentation"
defaultValue="2"
value={`${settings.editorIndentation}`}
options={tabIndentOptions}
onChange={(v) =>
patchModel(settings, { editorIndentation: clamp(Number.parseInt(v, 10) || 2, 2, 10) })
}
/>
<Checkbox
checked={settings.editorSoftWrap}
title="Wrap editor lines"
Expand Down
23 changes: 16 additions & 7 deletions src-web/components/core/Editor/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { startCompletion } from '@codemirror/autocomplete';
import { defaultKeymap, historyField, indentWithTab } from '@codemirror/commands';
import { foldState, forceParsing } from '@codemirror/language';
import { foldState, forceParsing, indentUnit } from '@codemirror/language';
import type { EditorStateConfig, Extension } from '@codemirror/state';
import { Compartment, EditorState } from '@codemirror/state';
import { EditorView, keymap, placeholder as placeholderExt, tooltips } from '@codemirror/view';
Expand Down Expand Up @@ -68,12 +68,13 @@ export interface EditorProps {
autocompleteVariables?: boolean | ((v: WrappedEnvironmentVariable) => boolean);
className?: string;
defaultValue?: string | null;
tabIndent?: number;
disableTabIndent?: boolean;
disabled?: boolean;
extraExtensions?: Extension[] | Extension;
forcedEnvironmentId?: string;
forceUpdateKey?: string | number;
format?: (v: string) => Promise<string>;
format?: (v: string, indent?: number) => Promise<string>;
heightMode?: 'auto' | 'full';
hideGutter?: boolean;
id?: string;
Expand Down Expand Up @@ -114,6 +115,7 @@ function EditorInner({
autocompleteVariables,
className,
defaultValue,
tabIndent,
disableTabIndent,
disabled,
extraExtensions,
Expand Down Expand Up @@ -154,6 +156,8 @@ function EditorInner({
wrapLines = settings.editorSoftWrap;
}

tabIndent = tabIndent ?? settings.editorIndentation;

if (disabled) {
readOnly = true;
}
Expand Down Expand Up @@ -273,11 +277,14 @@ function EditorInner({
if (disableTabIndent && current !== emptyExtension) return; // Nothing to do
if (!disableTabIndent && current === emptyExtension) return; // Nothing to do

const ext = !disableTabIndent ? keymap.of([indentWithTab]) : emptyExtension;
const ext = !disableTabIndent
? [keymap.of([indentWithTab]), indentUnit.of(' '.repeat(tabIndent))]
: emptyExtension;

const effects = tabIndentCompartment.current.reconfigure(ext);
cm.current?.view.dispatch({ effects });
},
[disableTabIndent],
[disableTabIndent, tabIndent],
);

const onClickFunction = useCallback(
Expand Down Expand Up @@ -384,7 +391,9 @@ function EditorInner({
placeholderCompartment.current.of(placeholderExt(placeholderElFromText(placeholder))),
wrapLinesCompartment.current.of(wrapLines ? EditorView.lineWrapping : emptyExtension),
tabIndentCompartment.current.of(
!disableTabIndent ? keymap.of([indentWithTab]) : emptyExtension,
!disableTabIndent
? [keymap.of([indentWithTab]), indentUnit.of(' '.repeat(tabIndent))]
: emptyExtension,
),
keymapCompartment.current.of(
keymapExtensions[settings.editorKeymap] ?? keymapExtensions.default,
Expand Down Expand Up @@ -481,7 +490,7 @@ function EditorInner({
onClick={async () => {
if (cm.current === null) return;
const { doc } = cm.current.view.state;
const formatted = await format(doc.toString());
const formatted = await format(doc.toString(), tabIndent);
// Update editor and blur because the cursor will reset anyway
cm.current.view.dispatch({
changes: { from: 0, to: doc.length, insert: formatted },
Expand All @@ -505,7 +514,7 @@ function EditorInner({
}),
);
return results;
}, [actions, format, onChange]);
}, [actions, format, tabIndent, onChange]);

const cmContainer = (
<div
Expand Down
6 changes: 5 additions & 1 deletion src-web/hooks/useFormatText.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { useQuery } from '@tanstack/react-query';
import type { EditorProps } from '../components/core/Editor/Editor';
import { tryFormatJson, tryFormatXml } from '../lib/formatters';
import { useAtomValue } from 'jotai';
import { settingsAtom } from '@yaakapp-internal/models';

export function useFormatText({
text,
Expand All @@ -11,9 +13,11 @@ export function useFormatText({
language: EditorProps['language'];
pretty: boolean;
}) {
const settings = useAtomValue(settingsAtom);

return useQuery({
placeholderData: (prev) => prev, // Keep previous data on refetch
queryKey: [text, language, pretty],
queryKey: [text, language, pretty, settings.editorIndentation],
queryFn: async () => {
if (text === '' || !pretty) {
return text;
Expand Down
14 changes: 10 additions & 4 deletions src-web/lib/formatters.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import vkBeautify from 'vkbeautify';
import { invokeCmd } from './tauri';
import { getSettings } from './settings';

export async function tryFormatJson(text: string): Promise<string> {
if (text === '') return text;

const settings = await getSettings();
const indent = settings.editorIndentation;

try {
const result = await invokeCmd<string>('cmd_format_json', { text });
return result;
return await invokeCmd<string>('cmd_format_json', { text, indent });
} catch (err) {
console.warn('Failed to format JSON', err);
}

try {
return JSON.stringify(JSON.parse(text), null, 2);
return JSON.stringify(JSON.parse(text), null, indent);
} catch (err) {
console.log('JSON beautify failed', err);
}
Expand All @@ -23,8 +26,11 @@ export async function tryFormatJson(text: string): Promise<string> {
export async function tryFormatXml(text: string): Promise<string> {
if (text === '') return text;

const settings = await getSettings();
const indent = settings.editorIndentation;

try {
return vkBeautify.xml(text, ' ');
return vkBeautify.xml(text, ' '.repeat(indent));
} catch (err) {
console.warn('Failed to format XML', err);
}
Expand Down