Skip to content

Commit

Permalink
Merge pull request #308 from zowe/copyLink
Browse files Browse the repository at this point in the history
 open file at a specific line using copied link/URL
  • Loading branch information
DivergentEuropeans authored Nov 26, 2022
2 parents acccdec + bb05caa commit 2261a04
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## `3.0.1`
- Bugfix: Added a few rules for JCL syntax highlighter
- Bugfix: Set USS path to correct directory, when opening the directory or file in new browser tab respectively
- Added the feature to copy the line content and copy URL link to open a file at a specific line

## `3.0.0`

Expand Down
14 changes: 11 additions & 3 deletions webClient/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ export class AppComponent {
}

handleLaunchOrMessageObject(data: any) {
/**
* selectedLines=[2] -> selected line is number 2 (in URL the info will look like "lines":"2")
* selectedLines=[2,7] -> selected lines are number 2-7 (TODO: Need to add the option to copy multiple lines and pass the info in the URL like "lines":"2-7")
*/
let selectedLines = [];
if(data.lines){
selectedLines = data.lines.split("-")
}
switch (data.type) {
case 'test-language':
this.log.info(`Setting language test mode`);
Expand Down Expand Up @@ -87,7 +95,7 @@ export class AppComponent {
let fileName = data.name.substring(lastSlash+1);
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].fileName == fileName) {
this.editorControl.openFile('', nodes[i]).subscribe(x => {
this.editorControl.openFile('', nodes[i], selectedLines).subscribe(x => {
this.log.debug(`file loaded through app2app.`);
});
this.editorControl.loadDirectory(nodes[i].path ? nodes[i].path : '/');
Expand All @@ -99,13 +107,13 @@ export class AppComponent {
});
} else {
this.log.info(`Opening dataset=${data.name}`);
this.editorControl.openDataset.next(data.name);
this.editorControl.openDataset.next({datasetName: data.name, selectedLines: selectedLines});
}
break;
case 'openDataset':
if (data.name) {
this.log.info(`Opening dataset=${data.name}`);
this.editorControl.openDataset.next(data.name);
this.editorControl.openDataset.next({datasetName: data.name, selectedLines: selectedLines});
} else {
this.log.warn(`Dataset name missing. Skipping operation`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
background-color: yellow;
color: black;
}
::ng-deep .myLineDecoration {
background: #e6e1ad; width: 50px !important;
}
}
.loading-indicator {
position: absolute;
Expand Down
52 changes: 51 additions & 1 deletion webClient/src/app/editor/code-editor/monaco/monaco.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import * as monaco from 'monaco-editor';
import { Subscription } from 'rxjs';
import { EditorKeybindingService } from '../../../shared/editor-keybinding.service';
import { KeyCode } from '../../../shared/keycode-enum';
import { SnackBarService } from '../../../shared/snack-bar.service';
import { MessageDuration } from "../../../shared/message-duration";
const ReconnectingWebSocket = require('reconnecting-websocket');

@Component({
Expand Down Expand Up @@ -65,7 +67,9 @@ export class MonacoComponent implements OnInit, OnChanges {
private editorControl: EditorControlService,
private languageService: LanguageServerService,
private appKeyboard: EditorKeybindingService,
public snackBar: SnackBarService,
@Inject(Angular2InjectionTokens.LOGGER) private log: ZLUX.ComponentLogger,
@Inject(Angular2InjectionTokens.PLUGIN_DEFINITION) private pluginDefinition: ZLUX.ContainerPluginDefinition,
@Inject(Angular2InjectionTokens.VIEWPORT_EVENTS) private viewportEvents: Angular2PluginViewportEvents) {
this.keyBindingSub.add(this.appKeyboard.keydownEvent.subscribe((event) => {
if (event.which === KeyCode.KEY_V) {
Expand Down Expand Up @@ -116,6 +120,21 @@ export class MonacoComponent implements OnInit, OnChanges {
this.editorControl.refreshLayout.subscribe(() =>{
setTimeout(() => this.editor.layout(), 1);
});

this.editor.onContextMenu((e: any) => {
if(e.target.type === 3){ //if right click is on top of the line numbers
this.viewportEvents.spawnContextMenu(e.event.browserEvent.clientX, e.event.browserEvent.clientY, [
{
text: 'Copy permalink',
action: () => this.copyPermalink(e)
},
{
text: 'Copy line',
action: () => this.copyLine(e)
}
], true)
}
});
}

focus(e: any) {
Expand All @@ -125,7 +144,6 @@ export class MonacoComponent implements OnInit, OnChanges {
this.editor.layout();
}


ngOnChanges(changes: SimpleChanges) {
for (const input in changes) {
if (input === 'editorFile' && changes[input].currentValue != null) {
Expand All @@ -143,6 +161,7 @@ export class MonacoComponent implements OnInit, OnChanges {
}
}


onMonacoInit(editor) {
this.editorControl.editor.next(editor);
this.keyBinds(editor);
Expand Down Expand Up @@ -231,6 +250,37 @@ export class MonacoComponent implements OnInit, OnChanges {
});
}

copyPermalink(event: any){
const lines = event.target.position.lineNumber;
const activeFile = this.editorControl.fetchActiveFile();
let filePath = '';
let link = '';
if(activeFile.model.isDataset){
filePath = activeFile.model.path;
link = `${window.location.origin}${window.location.pathname}?pluginId=${this.pluginDefinition.getBasePlugin().getIdentifier()}:data:{"type":"openDataset","name":"${encodeURIComponent(filePath)}","lines":"${lines}","toggleTree":true}`;
} else {
filePath = activeFile.model.path + "/" + activeFile.model.name;
link = `${window.location.origin}${window.location.pathname}?pluginId=${this.pluginDefinition.getBasePlugin().getIdentifier()}:data:{"type":"openFile","name":"${encodeURIComponent(filePath)}","lines":"${lines}","toggleTree":true}`;
}
navigator.clipboard.writeText(link).then(() => {
this.log.debug("Permalink copied to clipboard");
}).catch((error) => {
console.error("Failed to copy permalink Error: " + error);
this.snackBar.open("Failed to copy permalink. Error: " + error, 'Dismiss', { duration: MessageDuration.Short, panelClass: 'center' });
});
}

copyLine(event: any){
const lines = event.target.position.lineNumber;
const lineContent = this.editor.getModel().getLineContent(lines);
navigator.clipboard.writeText(lineContent).then(() => {
this.log.debug("Line copied to clipboard");
}).catch((error) => {
console.error("Failed to copy line. Error: " + error);
this.snackBar.open("Failed to copy line. Error: " + error, 'Dismiss', { duration: MessageDuration.Short, panelClass: 'center' });
});
}

saveFile() {
let fileContext = this.editorControl.fetchActiveFile();
let directory = fileContext.model.path || this.editorControl.activeDirectory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -561,10 +561,16 @@ export class MonacoService implements OnDestroy {
this.editorControl.removeActiveFromAllFiles();
fileNode.changed = true;
fileNode.active = true;
this.cleanDecoration();
}

cleanDecoration() {
this.editorControl.editor.getValue().deltaDecorations(this.decorations, []);
let editorValue = this.editorControl.editor.getValue();
let decorationIds=[];
editorValue.getModel().getAllDecorations().forEach((decoration) => {
decorationIds.push(decoration.id);
});
editorValue.deltaDecorations(decorationIds, []);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ export class ProjectTreeComponent {
}
});

this.editorControl.openDataset.subscribe(dirName => {
this.editorControl.openDataset.subscribe(datasetInfo => {
let dirName= datasetInfo.datasetName;
const selectedLines = datasetInfo.selectedLines;
if (dirName != null && dirName !== '') {
if (dirName[0] != '/') {
dirName = dirName.toUpperCase();
Expand All @@ -181,9 +183,9 @@ export class ProjectTreeComponent {
this.nodes = isMember ? this.dataAdapter.convertDatasetMemberList(response) : this.dataAdapter.convertDatasetList(response);
this.editorControl.setProjectNode(this.nodes);
if(isMember){
this.editorControl.openFile('',this.nodes.find(item => item.name === dsMemberName)).subscribe(x=> {this.log.debug('Dataset Member opened')});
this.editorControl.openFile('',this.nodes.find(item => item.name === dsMemberName), datasetInfo.selectedLines).subscribe(x=> {this.log.debug('Dataset Member opened')});
} else{
this.editorControl.openFile('',this.nodes[0]).subscribe(x=> {this.log.debug('Dataset opened')});
this.editorControl.openFile('',this.nodes[0], datasetInfo.selectedLines).subscribe(x=> {this.log.debug('Dataset opened')});
}
}, e => {
// TODO
Expand Down
34 changes: 30 additions & 4 deletions webClient/src/app/shared/editor-control/editor-control.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export class EditorControlService implements ZLUX.IEditor, ZLUX.IEditorMultiBuff
public createDirectory: EventEmitter<string> = new EventEmitter();
public openProject: EventEmitter<string> = new EventEmitter();
public openDirectory: EventEmitter<string> = new EventEmitter();
public openDataset: EventEmitter<string> = new EventEmitter();
public openDataset: EventEmitter<any> = new EventEmitter();
public toggleFileTreeSearch: EventEmitter<string> = new EventEmitter();
public closeAllFiles: EventEmitter<string> = new EventEmitter();
public undoCloseAllFiles: EventEmitter<string> = new EventEmitter();
Expand Down Expand Up @@ -1042,9 +1042,10 @@ export class EditorControlService implements ZLUX.IEditor, ZLUX.IEditorMultiBuff
*
* @param file The path of the file that should be opened
* @param targetBuffer The buffer into which the file should be opened, or null to open a new buffer
* @param selectedLines Array that stores the first and last selected lines
* @returns An observable that pushes a handle to the buffer into which the file was opened
*/
openFile(file: string, targetBuffer: ZLUX.EditorBufferHandle | null): Observable<ZLUX.EditorBufferHandle> {
openFile(file: string, targetBuffer: ZLUX.EditorBufferHandle | null, selectedLines?: any): Observable<ZLUX.EditorBufferHandle> {
// targetBuffer is a context of project in GCE.
let resultOpenObs: Observable<ZLUX.EditorBufferHandle>;
let fileOpenSub: Subscription;
Expand All @@ -1054,11 +1055,36 @@ export class EditorControlService implements ZLUX.IEditor, ZLUX.IEditorMultiBuff
resultOpenObs = new Observable((observer) => {
resultObserver = observer;
});

fileOpenSub = this.fileOpened.subscribe((e: ZLUX.EditorFileOpenedEvent) => {
let model = e.buffer.model;
lastFile = `${model.fileName}:${model.path}`;

//If we are opening a file with selected line or lines via URL link to file
if(selectedLines && selectedLines.length > 0){
let firstLine = 1;
let lastLine = 1;
if(selectedLines.length == 1){
firstLine = Number(selectedLines[0]);
lastLine = firstLine;
} else if(selectedLines.length == 2){
firstLine = Number(selectedLines[0]);
lastLine = Number(selectedLines[1]);
}
let editor = this.editor.getValue();
this.editor.subscribe((value)=> {
value.revealRangeAtTop(new monaco.Range(firstLine, 1, lastLine, 1));
value.deltaDecorations(
[],
[
{
range: new monaco.Range(firstLine, 1, lastLine, 1000000),
options: {
marginClassName: 'myLineDecoration'
}
}
]
);
})
}
// if have subscriber
if (resultObserver) {
if (e.buffer != null && e.buffer.id === targetBuffer.id) {
Expand Down

0 comments on commit 2261a04

Please sign in to comment.