Skip to content

Instantly share code, notes, and snippets.

@danielocdh
Created May 31, 2024 15:53
Show Gist options
  • Select an option

  • Save danielocdh/1cd1981c31e05baa44ee242947316154 to your computer and use it in GitHub Desktop.

Select an option

Save danielocdh/1cd1981c31e05baa44ee242947316154 to your computer and use it in GitHub Desktop.

fix for microsoft/vscode#125997, I wanted the panes to never auto resize when focused and at their minimum height/width

How it works

The script detects when a pane height/width is set to its minimum, then it tries to increase the pane height/width a bit so an auto resize is prevented the next time the pane is focused

How to run

Manually paste the code on the Developer Tools console OR save the code to a file and run it with something like apc.imports of drcika.apc-extension

How to stop

You can run the code again with the option script_disable set to true OR just don't run it again and reload/restart the vscode window

(() => {
//observing the dom enables the fix on situations other than manually resizing the panes,
//but it is slower as it will observe changes in the dom often
const observer_enabled = true;
//sometimes the "maximum" class is not added to .monaco-sash,
//so the .split-view-view height or width has to be tested
//use -1 to not test
const minimum_height = 70;
const minimum_width = 220;
//set to true and run the script again to only disable events/observer
const script_disable = false;
//end of settings
//check height/width
const minimum_height_or_width = minimum_height !== -1 || minimum_width !== -1;
//store for event functions and observer to be able to remove them if ran again
const data_ob_key = 'fix_for_125997';
window[data_ob_key] = window[data_ob_key] || {};
const data_ob = window[data_ob_key];
//clear previous events and observer
if (data_ob.event_on_mousedown) {
document.removeEventListener('mousedown', data_ob.event_on_mousedown, {capture: true});
delete data_ob.event_on_mousedown;
}
if (data_ob.event_on_mouseup) {
document.removeEventListener('mouseup', data_ob.event_on_mouseup, {capture: true});
delete data_ob.event_on_mouseup;
}
if (data_ob.observer) {
data_ob.observer.disconnect();
delete data_ob.observer;
}
//script disabled
if (script_disable) {
delete window[data_ob_key];
return;
}
//prevent mutation observer from reacting if sash manually moved recently
const sash_mmoved = {
recent: false,
time: 600,
timer: undefined,
done: () => {
if (!observer_enabled) { return; }
sash_mmoved.recent = true;
clearTimeout(sash_mmoved.timer);
sash_mmoved.timer = setTimeout(() => sash_mmoved.recent = false, sash_mmoved.time);
}
};
//mouse events/data
let doc_is_mousedown = false;
let doc_mousedown_on_sash = false;
let gvc_sash_simulated_moving = false;
data_ob.event_on_mousedown = e => {
if (gvc_sash_simulated_moving) { return; }
if (e.target.classList.contains('monaco-sash') && !e.target.classList.contains('disabled')) {
doc_mousedown_on_sash = true;
}
doc_is_mousedown = true;
};
data_ob.event_on_mouseup = () => {
if (gvc_sash_simulated_moving) { return; }
doc_is_mousedown = false;
if (doc_mousedown_on_sash) {
doc_mousedown_on_sash = false;
//mark sash as moved recently
sash_mmoved.done();
//fix
fix_min_max_timed();
}
};
document.addEventListener('mousedown', data_ob.event_on_mousedown, {capture: true, passive: true});
document.addEventListener('mouseup', data_ob.event_on_mouseup, {capture: true, passive: true});
//simulate resize
const simulate_ev = (el, {opts = {}, type = 'mousemove'} = {}) => {
const ev = new MouseEvent(type, Object.assign({bubbles: true, cancelable: false}, opts));
el.dispatchEvent(ev);
};
const simulate_resize = (el, {x = 0, y = 0} = {}) => {
if (!x && !y) { return; }
simulate_ev(el, {type: 'mousedown', opts: {clientX: 0, clientY: 0}});
simulate_ev(el, {type: 'mousemove', opts: {clientX: x, clientY: y}});
simulate_ev(el, {type: 'mouseup', opts: {clientX: x, clientY: y}});
};
//fix
const grid_view_container = document.querySelector('.grid-view-container');
const arr_sort_pos = (arr, is_vertical) => {
const pos_prop = is_vertical ? 'top' : 'left';
arr.sort((a, b) => (parseInt(b.style[pos_prop], 10) - parseInt(a.style[pos_prop], 10)));
return arr;
};
const dom_child_match = (parent_el, sel) => {
for (const el of parent_el.children) {
if (el.matches(sel)) { return el; }
}
return null;
};
const dom_children_match = (parent_el, sel) => {
const ret = [];
for (const el of parent_el.children) {
if (el.matches(sel)) { ret.push(el); }
}
return ret;
};
const dom_lineal_match = (parent_el, sel_arr) => {
let pel_tmp = parent_el;
for (const sel of sel_arr) {
pel_tmp = dom_child_match(pel_tmp, sel);
if (!pel_tmp) { break; }
}
return pel_tmp;
};
const fix_min_max_get_els_list = (split_view, arr, {
data_split_view_parent = false, lvl = 0, el_sash = false
} = {}) => {
let el_tmp = dom_lineal_match(split_view, ['.monaco-grid-branch-node', '.monaco-split-view2.separator-border']);
const is_vertical = el_tmp && el_tmp.classList.contains('vertical');
const sash_cont = el_tmp && dom_child_match(el_tmp, '.sash-container');
el_tmp = el_tmp && dom_lineal_match(el_tmp, ['.monaco-scrollable-element', '.split-view-container']);
el_tmp = el_tmp && dom_children_match(el_tmp, '.split-view-view.visible');
//found
const split_view_children = el_tmp || [];
if (!split_view_children.length || !sash_cont) { return; }
const sashes = dom_children_match(sash_cont, '.monaco-sash');
if (!sashes.length) { return; }
arr_sort_pos(sashes, is_vertical);
arr_sort_pos(split_view_children, is_vertical);
//save
if (!arr[lvl]) { arr[lvl] = []; }
const data_split_view = {
data_split_view_parent, el: split_view, el_sash,
is_vertical, sash_cont, sashes, views: split_view_children
};
arr[lvl].push(data_split_view);
//do children views
for (let i = 0; i < split_view_children.length; i++) {
const split_view_child = split_view_children[i];
let child_el_sash = sashes[i];
let child_el_sash_is_first = false;
if (!child_el_sash) {
child_el_sash = sashes.slice(-1)[0];
child_el_sash_is_first = true;
}
fix_min_max_get_els_list(split_view_child, arr, {
data_split_view_parent: data_split_view,
el_sash: child_el_sash, el_sash_is_first: child_el_sash_is_first,
lvl: lvl + 1
});
}
};
const fix_min_max_get_split_views = () => {
const split_views_arr = [];
fix_min_max_get_els_list(
dom_child_match(grid_view_container, '.monaco-grid-view'),
split_views_arr
);
split_views_arr.reverse();
return split_views_arr;
};
const fix_min_max_expand = item => {
const px_add = item.is_maximum ? -1 : 1;
const opts = item.is_vertical ? {y: px_add} : {x: px_add};
simulate_resize(item.el, opts);
};
const fix_min_max_expand_ancestor = (
data_split_view, sash_first_is_vertical, sash_count
) => {
let data_split_view_ancestor = data_split_view;
while (data_split_view_ancestor) {
const {el_sash} = data_split_view_ancestor;
//find ancestor view sash with same orientation
if (el_sash) {
const el_sash_is_vertical = el_sash.classList.contains('vertical');
if (sash_first_is_vertical === el_sash_is_vertical) {
//resize non disabled
if (!el_sash.classList.contains('disabled')) {
const {el_sash_is_first} = data_split_view_ancestor;
const px_add = (sash_count + 1) * (el_sash_is_first ? 1 : -1);
const opts = el_sash_is_vertical ? {x: px_add} : {y: px_add};
simulate_resize(el_sash, opts);
}
//stop
break;
}
}
data_split_view_ancestor = data_split_view_ancestor.data_split_view_parent;
}
};
let fix_min_max_timer;
let fix_min_max_pending;
const fix_min_max_time = 50;
const fix_min_max_timed = (delay = fix_min_max_time) => {
fix_min_max_pending = true;
clearTimeout(fix_min_max_timer);
fix_min_max_timer = setTimeout(() => {
fix_min_max();
fix_min_max_pending = false;
}, delay);
};
const fix_min_max = () => {
gvc_sash_simulated_moving = true;
//split view data, by level: deeper first, sorted by arr_sort_pos
const split_views_arr = fix_min_max_get_split_views();
for (const split_views_lvl_arr of split_views_arr) {
for (const data_split_view of split_views_lvl_arr) {
const {is_vertical, sashes, views} = data_split_view;
const items_to_fix = [];
for (let sash_i = 0; sash_i < sashes.length; sash_i++) {
const sash = sashes[sash_i];
//disabled, expand ancestor
let is_disabled = sash.classList.contains('disabled');
if (is_disabled) {
fix_min_max_expand_ancestor(
data_split_view, sash.classList.contains('vertical'), sashes.length
);
}
//still disabled, keep going
is_disabled = sash.classList.contains('disabled');
if (is_disabled) { continue; }
//by class
const is_minimum = sash.classList.contains('minimum');
let is_maximum = sash.classList.contains('maximum');
//by size
if (!is_maximum && !is_minimum) {
const view_prev = views[sash_i];
if (
minimum_height_or_width && (is_vertical ? minimum_height : minimum_width) !== -1 &&
view_prev && view_prev.style[is_vertical ? 'height' : 'width'] === `${
is_vertical ? minimum_height : minimum_width
}px`
) {
is_maximum = true;
}
}
//can/needs to be fixed
if (is_minimum !== is_maximum) {
items_to_fix[is_maximum ? 'push' : 'unshift']({el: sash, is_maximum, is_vertical});
}
}
for (const item of items_to_fix) { fix_min_max_expand(item); }
}
}
gvc_sash_simulated_moving = false;
};
//observer
if (observer_enabled) {
data_ob.observer = new MutationObserver(records => {
//mouse is down, sash moved recently, fix pending
if (doc_is_mousedown || sash_mmoved.recent || fix_min_max_pending) {
return;
}
//search records
let fix_it = false;
for (const record of records) {
const target = record.target;
//added/removed nodes
if (record.type === 'childList') {
if (
(record.addedNodes.length || record.removedNodes.length) &&
target.matches('.split-view-container, .sash-container')
) {
fix_it = true;
break;
}
}
else if (record.type === 'attributes') {
//class
if (record.attributeName === 'class') {
if (
target.classList.contains('monaco-sash') && !target.classList.contains('disabled') &&
target.className !== record.oldValue &&
!target.classList.contains('hover') &&
!record.oldValue.match(/\bhover\b/) &&
target.classList.contains('minimum') !== target.classList.contains('maximum')
) {
fix_it = true;
break;
}
}
//style
else if (record.attributeName === 'style' && target.classList.contains('split-view-view')) {
const is_vertical = target.matches(
'.monaco-split-view2.vertical > .monaco-scrollable-element > .split-view-container > .split-view-view'
);
if (
(is_vertical ? minimum_height : minimum_width) !== -1 &&
target.style[is_vertical ? 'height' : 'width'] === `${is_vertical ? minimum_height : minimum_width}px`
) {
fix_it = true;
break;
}
}
}
}
if (fix_it) { fix_min_max_timed(); }
});
data_ob.observer.observe(grid_view_container, {
attributeFilter: ['class'].concat(minimum_height_or_width ? ['style'] : []),
attributeOldValue: true,
subtree: true,
childList: true
});
}
//initial fix
fix_min_max_timed();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment