Skip to content
Closed
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
4 changes: 2 additions & 2 deletions src-node/package-lock.json

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

48 changes: 48 additions & 0 deletions src/extensionsIntegrated/Bookmarks/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
define(function (require, exports, module) {
const AppInit = require("utils/AppInit");
const CommandManager = require("command/CommandManager");
const Menus = require("command/Menus");
const Strings = require("strings");

const Bookmarks = require("./src/bookmarks");

// command ids
const CMD_TOGGLE_BOOKMARK = "bookmarks.toggleBookmark";
const CMD_NEXT_BOOKMARK = "bookmarks.nextBookmark";
const CMD_PREV_BOOKMARK = "bookmarks.prevBookmark";

// default keyboard shortcuts
const TOGGLE_BOOKMARK_KB_SHORTCUT = "Ctrl-Alt-B";
const NEXT_BOOKMARK_KB_SHORTCUT = "Ctrl-Alt-N";
const PREV_BOOKMARK_KB_SHORTCUT = "Ctrl-Alt-P";

/**
* This function is responsible for registering all the required commands
*/
function _registerCommands() {
CommandManager.register(Strings.TOGGLE_BOOKMARK, CMD_TOGGLE_BOOKMARK, Bookmarks.toggleBookmark);
CommandManager.register(Strings.GOTO_NEXT_BOOKMARK, CMD_NEXT_BOOKMARK, Bookmarks.goToNextBookmark);
CommandManager.register(Strings.GOTO_PREV_BOOKMARK, CMD_PREV_BOOKMARK, Bookmarks.goToPrevBookmark);
}

/**
* This function is responsible to add the bookmarks menu items to the navigate menu
*/
function _addItemsToMenu() {
const navigateMenu = Menus.getMenu(Menus.AppMenuBar.NAVIGATE_MENU);
navigateMenu.addMenuDivider(); // add a line to separate the other items from the bookmark ones

navigateMenu.addMenuItem(CMD_TOGGLE_BOOKMARK, TOGGLE_BOOKMARK_KB_SHORTCUT);
navigateMenu.addMenuItem(CMD_NEXT_BOOKMARK, NEXT_BOOKMARK_KB_SHORTCUT);
navigateMenu.addMenuItem(CMD_PREV_BOOKMARK, PREV_BOOKMARK_KB_SHORTCUT);
}

function init() {
_registerCommands();
_addItemsToMenu();
}

AppInit.appReady(function () {
init();
});
});
179 changes: 179 additions & 0 deletions src/extensionsIntegrated/Bookmarks/src/bookmarks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
define(function (require, exports, module) {
const EditorManager = require("editor/EditorManager");
const Editor = require("editor/Editor").Editor;

const Helper = require("./helper");

const GUTTER_NAME = "CodeMirror-bookmarkGutter",
BOOKMARK_PRIORITY = 100;

/**
* This is where all the bookmarks will be stored
* it is an array of objects where each object will be stored firstly based on the file and then as per line no.
* the sorting is done to make sure we need not access the whole complete list when trying to move back and forth
*
* @type {[{file: {String}, line: {Number}}]}
*/
const BookmarksList = [];

// initialize the bookmark gutter
Editor.registerGutter(GUTTER_NAME, BOOKMARK_PRIORITY);

/**
* This function is responsible to remove the bookmark from the bookmarks list
*
* @private
* @param {String} file - the file path
* @param {Number} line - the line number
*/
function _removeFromBookmarksList(file, line) {
for (let i = 0; i < BookmarksList.length; i++) {
if (BookmarksList[i].file === file && BookmarksList[i].line === line) {
BookmarksList.splice(i, 1);
break;
}
}
}

/**
* This function is responsible to add the bookmark to the bookmarks list
* after adding that we also sort that first by file path and then by line number to make accessing efficient
*
* @private
* @param {String} file - the file path
* @param {Number} line - the line number
*/
function _addToBookmarksList(file, line) {
BookmarksList.push({ file: file, line: line });

BookmarksList.sort((a, b) => {
if (a.file === b.file) {
return a.line - b.line;
}
return a.file.localeCompare(b.file);
});
}

/**
* This function toggles a bookmark on a specific line
*
* @private
* @param {Editor} editor - The current editor instance
* @param {number} line - The line number to toggle bookmark on
*/
function _toggleLineBookmark(editor, line) {
const file = editor.document.file.fullPath; // this file path will be used when storing in the bookmarks list

// remove bookmark
if (Helper.hasBookmark(editor, line, GUTTER_NAME)) {
editor.setGutterMarker(line, GUTTER_NAME, "");
_removeFromBookmarksList(file, line);
} else {
// add bookmark
editor.setGutterMarker(line, GUTTER_NAME, Helper.createBookmarkMarker());
_addToBookmarksList(file, line);
}
}

/**
* This function is responsible to toggle bookmarks at the current cursor position(s)
*/
function toggleBookmark() {
const editor = EditorManager.getFocusedEditor();
if (!editor) {
return;
}

const selections = editor.getSelections();
const uniqueLines = Helper.getUniqueLines(selections);

// process each unique line
uniqueLines.forEach((line) => {
_toggleLineBookmark(editor, line);
});
}

/**
* This function gets executed when users click on the go to next bookmark button in the navigate menu,
* or its keyboard shortcut
* This finds the next bookmark in the current file and moves the cursor there
*/
function goToNextBookmark() {
const editor = EditorManager.getFocusedEditor();
if (!editor) {
return;
}

// get the file path and line as these values are needed when searching in the bookmarks list
const currentFile = editor.document.file.fullPath;
const currentLine = editor.getCursorPos().line;

// get all the bookmarks in current file (this is already sorted by line number)
const fileBookmarks = BookmarksList.filter((bookmark) => bookmark.file === currentFile);
if (fileBookmarks.length === 0) {
return;
}

// find the next bookmark after current position
let nextBookmark = null;

// find the first bookmark after current line
for (let i = 0; i < fileBookmarks.length; i++) {
if (fileBookmarks[i].line > currentLine) {
nextBookmark = fileBookmarks[i];
break;
}
}

// If no next bookmark found, we wrap around to get the first bookmark in this file
if (!nextBookmark && fileBookmarks.length > 0) {
nextBookmark = fileBookmarks[0];
}

// take the cursor to the bookmark
if (nextBookmark) {
editor.setCursorPos(nextBookmark.line, 0);
}
}

/**
* This function gets executed when users click on the go to previous bookmark button in the navigate menu,
* or its keyboard shortcut
* This finds the previous bookmark in the current file and moves the cursor there
*/
function goToPrevBookmark() {
const editor = EditorManager.getFocusedEditor();
if (!editor) {
return;
}

const currentFile = editor.document.file.fullPath;
const currentLine = editor.getCursorPos().line;

const fileBookmarks = BookmarksList.filter((bookmark) => bookmark.file === currentFile);
if (fileBookmarks.length === 0) {
return;
}

let prevBookmark = null;

for (let i = fileBookmarks.length - 1; i >= 0; i--) {
if (fileBookmarks[i].line < currentLine) {
prevBookmark = fileBookmarks[i];
break;
}
}

if (!prevBookmark && fileBookmarks.length > 0) {
prevBookmark = fileBookmarks[fileBookmarks.length - 1];
}

if (prevBookmark) {
editor.setCursorPos(prevBookmark.line, 0);
}
}

exports.toggleBookmark = toggleBookmark;
exports.goToNextBookmark = goToNextBookmark;
exports.goToPrevBookmark = goToPrevBookmark;
});
40 changes: 40 additions & 0 deletions src/extensionsIntegrated/Bookmarks/src/helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
define(function (require, exports, module) {
// the bookmark svg icon
const bookmarkSvg = require("text!styles/images/bookmark.svg");

/**
* This function creates a bookmark marker element
*
* @returns {HTMLElement} The bookmark marker element
*/
function createBookmarkMarker() {
return $("<div>").addClass("bookmark-icon").html(bookmarkSvg)[0];
}

/**
* This function checks whether a line has a bookmark
*
* @param {Editor} editor - The current editor instance
* @param {number} line - The line number to check
* @param {string} gutterName - The name of the gutter
* @returns {boolean} True if the line has a bookmark, false otherwise
*/
function hasBookmark(editor, line, gutterName) {
return !!editor.getGutterMarker(line, gutterName);
}

/**
* This function gets unique line numbers from all selections
* this is needed so that when multiple cursors are there at the same line, we can get the line only once
*
* @param {Array<{start: {line: number}}>} selections - Array of selections
* @returns {Array<number>} Array of unique line numbers
*/
function getUniqueLines(selections) {
return [...new Set(selections.map((selection) => selection.start.line))];
}

exports.createBookmarkMarker = createBookmarkMarker;
exports.hasBookmark = hasBookmark;
exports.getUniqueLines = getUniqueLines;
});
1 change: 1 addition & 0 deletions src/extensionsIntegrated/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ define(function (require, exports, module) {
require("./indentGuides/main");
require("./CSSColorPreview/main");
require("./TabBar/main");
require("./Bookmarks/main");
});
6 changes: 6 additions & 0 deletions src/nls/root/strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,12 @@ define({
"CLOSE_UNMODIFIED_TABS": "Close Unmodified Tabs",
"REOPEN_CLOSED_FILE": "Reopen Closed File",

// Bookmarks extension strings
"TOGGLE_BOOKMARK": "Toggle Bookmark",
"GOTO_PREV_BOOKMARK": "Go to Previous Bookmark",
"GOTO_NEXT_BOOKMARK": "Go to Next Bookmark",
"TOGGLE_BOOKMARKS_PANEL": "Toggle Bookmarks panel",

// CodeInspection: errors/warnings
"ERRORS_NO_FILE": "No File Open",
"ERRORS_PANEL_TITLE_MULTIPLE": "{0} Problems - {1}",
Expand Down
16 changes: 16 additions & 0 deletions src/styles/Extn-Bookmarks.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.bookmark-icon {
width: 0.75em;
height: 0.75em;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
margin-left: 0.2em;
margin-top: 0.35em;

svg {
width: 100%;
height: 100%;
fill: white;
}
}
1 change: 1 addition & 0 deletions src/styles/brackets.less
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
@import "Extn-TabBar.less";
@import "Extn-DisplayShortcuts.less";
@import "Extn-CSSColorPreview.less";
@import "Extn-Bookmarks.less";

/* Overall layout */

Expand Down
1 change: 1 addition & 0 deletions src/styles/images/bookmark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading