Skip to content
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5a1a26b
fix: profile button text not centralized
devvaannsh Jul 9, 2025
4252e76
feat: add cancel button in add snippet panel
devvaannsh Jul 9, 2025
ae7dbc4
fix: save button always remain disabled
devvaannsh Jul 9, 2025
4004cfd
feat: auto update API docs
devvaannsh Jul 10, 2025
e5d2653
fix: increase panel min size so that the save, cancel buttons are alw…
devvaannsh Jul 10, 2025
078502c
fix: update text in the no snippets present panel
devvaannsh Jul 10, 2025
f4db68f
fix: back button text not properly centralized
devvaannsh Jul 10, 2025
4236acd
feat: add check state on menu item when panel is open
devvaannsh Jul 10, 2025
f985b8b
fix: alignment of plus icon in the add snippet button
devvaannsh Jul 10, 2025
c619e32
fix: back button alignment
devvaannsh Jul 10, 2025
1ff336d
fix: move the content a bit right to maintain hierarchy structure
devvaannsh Jul 10, 2025
e7d59a3
fix: made close button styling consistent to other panels close button
devvaannsh Jul 10, 2025
a5932f5
fix: make filter input consistent to other panels filter input
devvaannsh Jul 10, 2025
5ad4a12
fix: set min width to the template textare to keep it consistent to o…
devvaannsh Jul 10, 2025
41bc07d
feat: disable reset button in edit panel when nothing to reset
devvaannsh Jul 10, 2025
11552b6
fix: ui layout issues in snippets list header
devvaannsh Jul 12, 2025
90a8a51
fix: font weight issue for snippet list
devvaannsh Jul 12, 2025
99c819a
feat: allow users to write file extension in any format
devvaannsh Jul 12, 2025
f941f01
fix: mutliple commas appearing when parsing failed
devvaannsh Jul 12, 2025
4148d56
fix: remove trailing dot from result
devvaannsh Jul 12, 2025
3191f02
feat: save snippets to file storage instead of prefs manager
devvaannsh Jul 12, 2025
2a12fd3
feat: replace reset button with cancel button in the edit snippets panel
devvaannsh Jul 12, 2025
ae58526
fix: prevent processing file extension where two dots are there to su…
devvaannsh Jul 12, 2025
589b6d1
refactor: replace template with Click to edit template and so on
devvaannsh Jul 12, 2025
8068629
refactor: store snippets directly in file instead of preferencesBase
devvaannsh Jul 13, 2025
206daed
fix: snippets 3 dots in the menu item was not consistent with the 3 d…
devvaannsh Jul 13, 2025
77a2391
fix: remove redundant then blocks
devvaannsh Jul 14, 2025
8c502ab
fix: remove unnecessary pretty printing when saving file
devvaannsh Jul 14, 2025
2947c2d
fix: directly return jsPromise for writeText instead of creating a ne…
devvaannsh Jul 14, 2025
d4491e1
feat: report unexpected errors to bugsnag
devvaannsh Jul 14, 2025
63d1a7b
feat: move all strings to strings.js file
devvaannsh Jul 14, 2025
81da0d5
fix: strings in html not appearing
devvaannsh Jul 14, 2025
1350ded
feat: add metrics to track snippets usage
devvaannsh Jul 14, 2025
10ecd71
fix: remove redundant console error as logger is already present
devvaannsh Jul 14, 2025
f280ab1
fix: replace reject with resolve as reject might break boot
devvaannsh Jul 14, 2025
3dc6e1d
fix: instead of hard-coding file names use language manager
devvaannsh Jul 14, 2025
76d6aae
fix: use stringUtils to replace strings
devvaannsh Jul 14, 2025
818ef69
fix: change cursor to pointer when close button for snippets panel is…
devvaannsh Jul 14, 2025
9c0b25a
fix: return a "file" type if the snippet is enabled only for specific…
devvaannsh Jul 15, 2025
be92f9a
fix: optimize the snippet code hints to prevent checking for hints on…
devvaannsh Jul 15, 2025
d518c53
fix: improve readability of isSnippetSupportedInLanguageContext function
devvaannsh Jul 15, 2025
862131d
fix: remove redundant try catch block from getCurrentLanguageContext …
devvaannsh Jul 15, 2025
d27e2b2
refactor: replace ?. with x && y
devvaannsh Jul 15, 2025
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
20 changes: 20 additions & 0 deletions docs/API-Reference/editor/CodeHintManager.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ insertHintOnTab Preference.
* [.registerHintProvider(provider, languageIds, priority)](#module_CodeHintManager..registerHintProvider)
* [.hasValidExclusion(exclusion, textAfterCursor)](#module_CodeHintManager..hasValidExclusion) ⇒ <code>boolean</code>
* [.isOpen()](#module_CodeHintManager..isOpen) ⇒ <code>boolean</code>
* [.showHintsAtTop(handler)](#module_CodeHintManager..showHintsAtTop)
* [.clearHintsAtTop()](#module_CodeHintManager..clearHintsAtTop)

<a name="module_CodeHintManager..registerHintProvider"></a>

Expand Down Expand Up @@ -263,3 +265,21 @@ Test if a hint popup is open.

**Kind**: inner method of [<code>CodeHintManager</code>](#module_CodeHintManager)
**Returns**: <code>boolean</code> - - true if the hints are open, false otherwise.
<a name="module_CodeHintManager..showHintsAtTop"></a>

### CodeHintManager.showHintsAtTop(handler)
Register a handler to show hints at the top of the hint list.
This API allows extensions to add their own hints at the top of the standard hint list.

**Kind**: inner method of [<code>CodeHintManager</code>](#module_CodeHintManager)

| Param | Type | Description |
| --- | --- | --- |
| handler | <code>Object</code> | A hint provider object with standard methods: - hasHints: function(editor, implicitChar) - returns true if hints are available - getHints: function(editor, implicitChar) - returns hint response object with hints array - insertHint: function(hint) - handles hint insertion, returns true if handled |

<a name="module_CodeHintManager..clearHintsAtTop"></a>

### CodeHintManager.clearHintsAtTop()
Unregister the hints at top handler.

**Kind**: inner method of [<code>CodeHintManager</code>](#module_CodeHintManager)
41 changes: 30 additions & 11 deletions src/extensionsIntegrated/CustomSnippets/driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,15 @@ define(function (require, exports, module) {
Global.SnippetHintsList.push(snippetData);
Helper.clearAllInputFields();
Helper.toggleSaveButtonDisability();
SnippetsState.saveSnippetsToState();

// save to file storage
SnippetsState.saveSnippetsToState()
.then(function () {
//
})
.catch(function (error) {
console.error("failed to save custom snippet correctly:", error);
});

// we need to move back to snippets list view after a snippet is saved
UIHelper.showSnippetListMenu();
Expand Down Expand Up @@ -87,7 +95,15 @@ define(function (require, exports, module) {
// update the snippet in the list
if (snippetIndex !== -1) {
Global.SnippetHintsList[snippetIndex] = editedData;
SnippetsState.saveSnippetsToState();

// save to file storage
SnippetsState.saveSnippetsToState()
.then(function () {
//
})
.catch(function (error) {
console.error("failed to save custom snippet correctly:", error);
});

// clear the stored data
$editView.removeData("originalSnippet");
Expand All @@ -100,19 +116,24 @@ define(function (require, exports, module) {
}

/**
* This function handles the reset button click for editing a snippet
* It restores the original snippet data in the edit form
* This function is responsible to handle the cancel button click in the edit-snippet panel
* this resets the format to the last saved values and then moves back to the snippets-list panel
*/
function handleResetBtnClick() {
function handleCancelEditBtnClick() {
const $editView = $("#custom-snippets-edit");
const originalSnippet = $editView.data("originalSnippet");

if (originalSnippet) {
// restore original data in the form
// restore original data in the form to reset any changes
Helper.populateEditForm(originalSnippet);
// update save button state
Helper.toggleEditSaveButtonDisability();
}

$editView.removeData("originalSnippet");
$editView.removeData("snippetIndex");

// navigate back to snippets list
UIHelper.showSnippetListMenu();
SnippetsList.showSnippetsList();
}

/**
Expand Down Expand Up @@ -164,10 +185,8 @@ define(function (require, exports, module) {
};
}



exports.getWordBeforeCursor = getWordBeforeCursor;
exports.handleSaveBtnClick = handleSaveBtnClick;
exports.handleEditSaveBtnClick = handleEditSaveBtnClick;
exports.handleResetBtnClick = handleResetBtnClick;
exports.handleCancelEditBtnClick = handleCancelEditBtnClick;
});
73 changes: 70 additions & 3 deletions src/extensionsIntegrated/CustomSnippets/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,67 @@ define(function (require, exports, module) {
return languageMap[languageId] || languageId;
}

/**
* This function is to make sure file extensions are properly formatted with leading dots
* because user may provide values in not very consistent manner, we need to handle all those cases
* For ex: what we expect: `.js, .html, .css`
* what user may provide: `js, html, css` or: `js html css` etc
*
* This function processes file extensions in various formats and ensures they:
* - Have a leading dot (if not empty or "all")
* - Are properly separated with commas and spaces
* - Don't contain empty or standalone dots
* - No consecutive commas
*
* @param {string} extension - The file extension(s) to process
* @returns {string} - The properly formatted file extension(s)
*/
function processFileExtensionInput(extension) {
if (!extension || extension === "all") {
return extension;
}

// Step 1: normalize the input by converting spaces to commas if no commas exist
if (extension.includes(" ")) {
extension = extension.replace(/\s+/g, ",");
}

let result = "";

// Step 2: process comma-separated extensions FIRST (before dot-separated)
// this prevents issues with inputs like ".js,.html,." or ".js,,.html"
if (extension.includes(",")) {
result = extension
.split(",")
.map((ext) => {
ext = ext.trim();
// skip all the standalone dots or empty entries
if (ext === "." || ext === "") {
return "";
}
// Add leading dot if missing
return ext.startsWith(".") ? ext : "." + ext;
})
.filter((ext) => ext !== "") // Remove empty entries
.join(", ");
} else {
// Step 3: Handle single extension
if (extension === ".") {
result = ""; // remove standalone dot
} else {
// Add leading dot if missing
result = extension.startsWith(".") ? extension : "." + extension;
}
}

// this is just the final safeguard to remove any consecutive commas and clean up spacing
result = result.replace(/,\s*,+/g, ",").replace(/,\s*$/, "").replace(/^\s*,/, "").trim();
// remove trailing dots (like .css. -> .css)
result = result.endsWith('.') ? result.slice(0, -1) : result;

return result;
}

/**
* This function is responsible to get the snippet data from all the required input fields
* it is called when the save button is clicked
Expand All @@ -108,11 +169,14 @@ define(function (require, exports, module) {
const templateText = $("#template-text-box").val().trim();
const fileExtension = $("#file-extn-box").val().trim();

// process the file extension so that we can get the value in the required format
const processedFileExtension = processFileExtensionInput(fileExtension);

return {
abbreviation: abbreviation,
description: description || "", // allow empty description
templateText: templateText,
fileExtension: fileExtension || "all" // default to "all" if empty
fileExtension: processedFileExtension || "all" // default to "all" if empty
};
}

Expand All @@ -128,7 +192,7 @@ define(function (require, exports, module) {
const $abbrInput = $("#abbr-box");
const $templateInput = $("#template-text-box");

const $saveBtn = $("#save-custom-snippet-btn button");
const $saveBtn = $("#save-custom-snippet-btn");

// make sure that the required fields has some value
const hasAbbr = $abbrInput.val().trim().length > 0;
Expand Down Expand Up @@ -374,11 +438,14 @@ define(function (require, exports, module) {
const templateText = $("#edit-template-text-box").val().trim();
const fileExtension = $("#edit-file-extn-box").val().trim();

// process the file extension so that we can get the value in the required format
const processedFileExtension = processFileExtensionInput(fileExtension);

return {
abbreviation: abbreviation,
description: description || "", // allow empty description
templateText: templateText,
fileExtension: fileExtension || "all" // default to "all" if empty
fileExtension: processedFileExtension || "all" // default to "all" if empty
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,16 @@
</div>
<div id="back-to-list-menu-btn" class="custom-snippet-btn hidden">
<button title="Back to snippets list">
<i class="fas fa-chevron-left"></i> Back
<i class="back-btn-left-icon fas fa-chevron-left"></i>
<span class="back-btn-text">Back</span>
</button>
</div>
</div>
<div class="buttons">
<div id="filter-snippets-panel" class="filter-snippets-panel">
<input id="filter-snippets-input" type="text" placeholder="Filter..." autocomplete="off" />
</div>
<div id="close-custom-snippets-panel-btn">
<button><i class="fas fa-times"></i></button>
</div>
<a href="#" class="close" id="close-custom-snippets-panel-btn">&times;</a>
</div>
</div>

Expand Down Expand Up @@ -111,8 +110,9 @@
</div>
</div>

<div id="save-custom-snippet-btn">
<button class="dialog-button btn primary" disabled>Save</button>
<div id="add-custom-snippet-panel-buttons">
<button id="cancel-custom-snippet-btn" class="dialog-button btn">Cancel</button>
<button id="save-custom-snippet-btn" class="dialog-button btn primary" disabled>Save</button>
</div>
</div>

Expand Down Expand Up @@ -163,7 +163,7 @@
</div>

<div id="edit-snippet-buttons">
<button id="reset-snippet-btn" class="dialog-button btn">Reset</button>
<button id="cancel-edit-snippet-btn" class="dialog-button btn">Cancel</button>
<button id="save-edit-snippet-btn" class="dialog-button btn primary" disabled>Save</button>
</div>
</div>
Expand Down
33 changes: 27 additions & 6 deletions src/extensionsIntegrated/CustomSnippets/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ define(function (require, exports, module) {

const MY_COMMAND_ID = "custom_snippets";
const PANEL_ID = "customSnippets.panel";
const MENU_ITEM_NAME = "Custom Snippets..."; // this name will appear as the menu item
const PANEL_MIN_SIZE = 100; // the minimum size more than which its height cannot be decreased
const MENU_ITEM_NAME = "Custom Snippets\u2026"; // this name will appear as the menu item
const PANEL_MIN_SIZE = 340; // the minimum size more than which its height cannot be decreased

// this is to store the panel reference,
// as we only need to create this once. rest of the time we can just toggle the visibility of the panel
Expand Down Expand Up @@ -72,8 +72,10 @@ define(function (require, exports, module) {
function _togglePanelVisibility() {
if (customSnippetsPanel.isVisible()) {
customSnippetsPanel.hide();
CommandManager.get(MY_COMMAND_ID).setChecked(false);
} else {
customSnippetsPanel.show();
CommandManager.get(MY_COMMAND_ID).setChecked(true);

$("#filter-snippets-input").val("");
UIHelper.initializeListViewToolbarTitle();
Expand All @@ -89,6 +91,7 @@ define(function (require, exports, module) {
*/
function _hidePanel() {
customSnippetsPanel.hide();
CommandManager.get(MY_COMMAND_ID).setChecked(false);
}

/**
Expand All @@ -101,6 +104,7 @@ define(function (require, exports, module) {
// if it is then we can just toggle its visibility
if (!customSnippetsPanel) {
_createPanel();
CommandManager.get(MY_COMMAND_ID).setChecked(true);
} else {
_togglePanelVisibility();
}
Expand All @@ -122,6 +126,7 @@ define(function (require, exports, module) {
function _registerHandlers() {
const $closePanelBtn = $("#close-custom-snippets-panel-btn");
const $saveCustomSnippetBtn = $("#save-custom-snippet-btn");
const $cancelCustomSnippetBtn = $("#cancel-custom-snippet-btn");
const $abbrInput = $("#abbr-box");
const $descInput = $("#desc-box");
const $templateInput = $("#template-text-box");
Expand All @@ -136,7 +141,7 @@ define(function (require, exports, module) {
const $editTemplateInput = $("#edit-template-text-box");
const $editFileExtnInput = $("#edit-file-extn-box");
const $saveEditSnippetBtn = $("#save-edit-snippet-btn");
const $resetSnippetBtn = $("#reset-snippet-btn");
const $cancelEditSnippetBtn = $("#cancel-edit-snippet-btn");

$addSnippetBtn.on("click", function () {
UIHelper.showAddSnippetMenu();
Expand All @@ -159,6 +164,11 @@ define(function (require, exports, module) {
Driver.handleSaveBtnClick();
});

$cancelCustomSnippetBtn.on("click", function () {
UIHelper.showSnippetListMenu();
SnippetsList.showSnippetsList();
});

$abbrInput.on("input", Helper.toggleSaveButtonDisability);
$templateInput.on("input", Helper.toggleSaveButtonDisability);

Expand Down Expand Up @@ -191,7 +201,9 @@ define(function (require, exports, module) {
});

$editAbbrInput.on("input", Helper.toggleEditSaveButtonDisability);
$editDescInput.on("input", Helper.toggleEditSaveButtonDisability);
$editTemplateInput.on("input", Helper.toggleEditSaveButtonDisability);
$editFileExtnInput.on("input", Helper.toggleEditSaveButtonDisability);

$editAbbrInput.on("keydown", function (e) {
Helper.validateAbbrInput(e, this);
Expand Down Expand Up @@ -225,8 +237,8 @@ define(function (require, exports, module) {
Driver.handleEditSaveBtnClick();
});

$resetSnippetBtn.on("click", function () {
Driver.handleResetBtnClick();
$cancelEditSnippetBtn.on("click", function () {
Driver.handleCancelEditBtnClick();
});

// filter input event handler
Expand All @@ -246,7 +258,16 @@ define(function (require, exports, module) {
$snippetsPanel = $(snippetsPanelTpl);
_addToMenu();
CodeHintIntegration.init();
SnippetsState.loadSnippetsFromState();

// load snippets from file storage
SnippetsState.loadSnippetsFromState()
.then(function () {
//
})
.catch(function (error) {
console.error("failed to load custom snippets:", error);
});

SnippetCursorManager.registerHandlers();
});
});
Loading
Loading