Skip to content

Commit

Permalink
feat: add "Copy Cell Value" context menu item to LanguageServers view
Browse files Browse the repository at this point in the history
  • Loading branch information
sebthom committed Jan 16, 2025
1 parent a096dad commit 30c3e79
Showing 1 changed file with 121 additions and 2 deletions.
123 changes: 121 additions & 2 deletions org.eclipse.lsp4e/src/org/eclipse/lsp4e/ui/LanguageServersView.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,20 @@
import org.eclipse.lsp4e.LanguageServerWrapper;
import org.eclipse.lsp4e.LanguageServiceAccessor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableCursor;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
Expand All @@ -57,6 +67,7 @@ public class LanguageServersView extends ViewPart {
private final Map<LanguageServerWrapper, ToolBar> actionButtons = new HashMap<>();
private final List<ColumnLabelProvider> columnLabelProviders = new ArrayList<>();

private @Nullable TableCursor tableCursor;
private int tableSortColumn = 1;
private int tableSortDirection = 1; // 1 = ascending, -1 = descending
private final ViewerComparator tableSorter = new ViewerComparator() {
Expand All @@ -80,6 +91,27 @@ public int compare(final @Nullable Viewer viewer, @Nullable final Object e1, @Nu
}
};

private void copyCurrentCellToClipboard() {
final TableCursor cursor = this.tableCursor;
if (cursor == null)
return;
final Table table = viewer.getTable();

final TableItem currentRow = cursor.getRow();
final int currentColumn = cursor.getColumn();
if (currentRow != null && currentColumn >= 0) {
final String cellContent = currentRow.getText(currentColumn);
if (cellContent != null && !cellContent.isEmpty()) {
final var clipboard = new Clipboard(table.getDisplay());
try {
clipboard.setContents(new Object[] { cellContent }, new Transfer[] { TextTransfer.getInstance() });
} finally {
clipboard.dispose();
}
}
}
}

private void createColumn(String name, int width, ColumnLabelProvider labelProvider) {
final var viewerColumn = new TableViewerColumn(viewer, SWT.NONE);
final var tableColumn = viewerColumn.getColumn();
Expand Down Expand Up @@ -118,7 +150,7 @@ public void createPartControl(Composite parent) {
createColumn(EMPTY, 26, new ColumnLabelProvider() {
@Override
public void update(final ViewerCell cell) {
if(cell.getElement() instanceof LanguageServerWrapper lsWrapper) {
if (cell.getElement() instanceof LanguageServerWrapper lsWrapper) {
final var item = (TableItem) cell.getItem();
final var buttons = actionButtons.computeIfAbsent(lsWrapper, unused -> {
final var toolBar = new ToolBar((Composite) cell.getViewerRow().getControl(), SWT.FLAT);
Expand Down Expand Up @@ -213,6 +245,8 @@ public String getText(Object element) {

viewer.setContentProvider(new ArrayContentProvider());

initContextMenu();

scheduleRefreshJob();
}

Expand All @@ -224,14 +258,81 @@ public void dispose() {
super.dispose();
}

private void initContextMenu() {
// Avoiding the use of MenuManager, table.setMenu(contextMenu), and
// SWT.MenuDetect because the table's SWT.FULL_SELECTION interferes with
// right-click detection, causing inconsistent behavior and preventing the
// context menu from being displayed reliably.
final Table table = viewer.getTable();
final var contextMenu = new Menu(table);
final var copyValueMenuItem = new MenuItem(contextMenu, SWT.NONE);
copyValueMenuItem.setText("Copy Cell Value"); //$NON-NLS-1$
copyValueMenuItem.addListener(SWT.Selection, event -> copyCurrentCellToClipboard());
table.addListener(SWT.MouseDown, event -> {
if (event.button == 3 /* Right-click? */
&& viewer.getCell(new Point(event.x, event.y)) != null /* Cell selected? */) {
contextMenu.setVisible(true);
}
});
}

private void initTableCursor() {
final TableCursor cursorOld = this.tableCursor;
if (cursorOld != null && !cursorOld.isDisposed()) {
cursorOld.dispose();
}
final Table table = viewer.getTable();

/*
* enable single cell selection via mouse and cell navigation via keyboard
*/
final var cursor = this.tableCursor = new TableCursor(table, SWT.NONE);
cursor.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
selectCell(table.indexOf(cursor.getRow()), cursor.getColumn());
}
});

/*
* enable CTRL+C to copy cell content
*/
cursor.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(final KeyEvent e) {
if ((e.stateMask & SWT.CTRL) != 0 && e.keyCode == 'c') { // Check for CTRL+C
copyCurrentCellToClipboard();
}
}
});
}

private void selectCell(int rowIdx, int colIdx) {
final var cursor = this.tableCursor;
if (cursor == null)
return;
final var table = viewer.getTable();
if (table.getItemCount() == 0)
return;

rowIdx = Math.max(0, Math.min(rowIdx, table.getItemCount() - 1));
colIdx = Math.max(1 /* exclude action buttons column */, Math.min(colIdx, table.getColumnCount() - 1));

table.setSelection(rowIdx);

cursor.setSelection(rowIdx, colIdx);
cursor.setVisible(true);
cursor.setFocus();
}

private void scheduleRefreshJob() {
final var viewerRefreshJob = this.viewerRefreshJob = new Job("Refresh Language Server Processes view") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
if (getSite().getPage().isPartVisible(LanguageServersView.this)) {
updateViewerInput();
}
schedule(2000);
schedule(2_000);
return Status.OK_STATUS;
}
};
Expand All @@ -252,7 +353,25 @@ private void updateViewerInput() {
UI.getDisplay().execute(() -> {
actionButtons.values().forEach(Widget::dispose);
actionButtons.clear();

final var table = viewer.getTable();

// save TableCursor position
int selectedRow = Math.max(0, table.getSelectionIndex());
int selectedCol = 1;
final var cursor = this.tableCursor;
if (cursor != null) {
selectedCol = cursor.getColumn();
}

viewer.setInput(newElements);
initTableCursor();

// restore TableCursor position
if (table.getSelectionIndex() > -1) {
selectedRow = table.getSelectionIndex();
}
selectCell(selectedRow, selectedCol);
});
}
}
Expand Down

0 comments on commit 30c3e79

Please sign in to comment.