git4refactor
filip mertens 7 months ago
parent f8a72e6043
commit 27e2c1d93d
  1. 7
      apps/etherscan/project.json
  2. 31
      apps/remix-ide/src/app/editor/editor.js
  3. 10
      apps/remix-ide/src/app/files/fileManager.ts
  4. 11
      apps/remix-ide/src/app/panels/layout.ts
  5. 17
      apps/remix-ide/src/app/panels/tab-proxy.js
  6. 14
      libs/remix-ui/editor/src/lib/actions/editor.ts
  7. 44
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  8. 6
      libs/remix-ui/git/src/lib/gitactions.ts

@ -38,6 +38,13 @@
} }
} }
}, },
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["apps/etherscan/**/*.{ts,tsx,js,jsx}"]
}
},
"serve": { "serve": {
"executor": "@nrwl/webpack:dev-server", "executor": "@nrwl/webpack:dev-server",
"defaultConfiguration": "development", "defaultConfiguration": "development",

@ -5,6 +5,7 @@ import { EditorUI } from '@remix-ui/editor' // eslint-disable-line
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json' import * as packageJson from '../../../../../package.json'
import { PluginViewWrapper } from '@remix-ui/helper' import { PluginViewWrapper } from '@remix-ui/helper'
import { commitChange } from '@remix-ui/git'
const EventManager = require('../../lib/events') const EventManager = require('../../lib/events')
@ -13,7 +14,7 @@ const profile = {
name: 'editor', name: 'editor',
description: 'service - editor', description: 'service - editor',
version: packageJson.version, version: packageJson.version,
methods: ['highlight', 'discardHighlight', 'clearAnnotations', 'addLineText', 'discardLineTexts', 'addAnnotation', 'gotoLine', 'revealRange', 'getCursorPosition', 'open', 'addModel','addErrorMarker', 'clearErrorMarkers', 'getText', 'getPositionAt'], methods: ['highlight', 'discardHighlight', 'clearAnnotations', 'addLineText', 'discardLineTexts', 'addAnnotation', 'gotoLine', 'revealRange', 'getCursorPosition', 'open', 'addModel','addErrorMarker', 'clearErrorMarkers', 'getText', 'getPositionAt', 'openReadOnly'],
} }
class Editor extends Plugin { class Editor extends Plugin {
@ -62,7 +63,8 @@ class Editor extends Plugin {
onBreakPointAdded: (file, line) => this.triggerEvent('breakpointAdded', [file, line]), onBreakPointAdded: (file, line) => this.triggerEvent('breakpointAdded', [file, line]),
onBreakPointCleared: (file, line) => this.triggerEvent('breakpointCleared', [file, line]), onBreakPointCleared: (file, line) => this.triggerEvent('breakpointCleared', [file, line]),
onDidChangeContent: (file) => this._onChange(file), onDidChangeContent: (file) => this._onChange(file),
onEditorMounted: () => this.triggerEvent('editorMounted', []) onEditorMounted: () => this.triggerEvent('editorMounted', []),
onDiffEditorMounted: () => this.triggerEvent('diffEditorMounted', [])
} }
// to be implemented by the react component // to be implemented by the react component
@ -80,8 +82,10 @@ class Editor extends Plugin {
editorAPI={state.api} editorAPI={state.api}
themeType={state.currentThemeType} themeType={state.currentThemeType}
currentFile={state.currentFile} currentFile={state.currentFile}
currentDiffFile={state.currentDiffFile}
events={state.events} events={state.events}
plugin={state.plugin} plugin={state.plugin}
isDiff={state.isDiff}
/> />
} }
@ -110,6 +114,8 @@ class Editor extends Plugin {
api: this.api, api: this.api,
currentThemeType: this.currentThemeType, currentThemeType: this.currentThemeType,
currentFile: this.currentFile, currentFile: this.currentFile,
currentDiffFile: this.currentDiffFile,
isDiff: this.isDiff,
events: this.events, events: this.events,
plugin: this plugin: this
}) })
@ -182,9 +188,10 @@ class Editor extends Plugin {
} }
_switchSession (path) { _switchSession (path) {
if (path === this.currentFile) return if (path !== this.currentFile) {
this.triggerEvent('sessionSwitched', []) this.triggerEvent('sessionSwitched', [])
this.currentFile = path this.currentFile = path
}
this.renderComponent() this.renderComponent()
} }
@ -240,10 +247,10 @@ class Editor extends Plugin {
* @param {string} content Content of the file to open * @param {string} content Content of the file to open
* @param {string} mode Mode for this file [Default is `text`] * @param {string} mode Mode for this file [Default is `text`]
*/ */
async _createSession (path, content, mode) { async _createSession (path, content, mode, readOnly) {
if (!this.activated) return if (!this.activated) return
this.emit('addModel', content, mode, path, this.readOnlySessions[path]) this.emit('addModel', content, mode, path, readOnly || this.readOnlySessions[path])
return { return {
path, path,
language: mode, language: mode,
@ -313,6 +320,7 @@ class Editor extends Plugin {
- URL prepended with "browser" - URL prepended with "browser"
- URL not prepended with the file explorer. We assume (as it is in the whole app, that this is a "browser" URL - URL not prepended with the file explorer. We assume (as it is in the whole app, that this is a "browser" URL
*/ */
this.isDiff = false
if (!this.sessions[path]) { if (!this.sessions[path]) {
this.readOnlySessions[path] = false this.readOnlySessions[path] = false
const session = await this._createSession(path, content, this._getMode(path)) const session = await this._createSession(path, content, this._getMode(path))
@ -334,9 +342,22 @@ class Editor extends Plugin {
const session = await this._createSession(path, content, this._getMode(path)) const session = await this._createSession(path, content, this._getMode(path))
this.sessions[path] = session this.sessions[path] = session
} }
this.isDiff = false
this._switchSession(path) this._switchSession(path)
} }
async openDiff(change) {
console.log('openDiff', change)
const hashedPathModified = change.readonly ? change.path + change.hashModified : change.path
const hashedPathOriginal = change.path + change.hashOriginal
const session = await this._createSession(hashedPathModified, change.modified, this._getMode(change.path), change.readonly)
await this._createSession(hashedPathOriginal, change.original, this._getMode(change.path), change.readonly)
this.sessions[hashedPathModified] = session
this.currentDiffFile = hashedPathOriginal
this.isDiff = true
this._switchSession(hashedPathModified)
}
/** /**
* Content of the current session * Content of the current session
* @return {String} content of the file referenced by @arg path * @return {String} content of the file referenced by @arg path

@ -9,8 +9,6 @@ import { fileChangedToastMsg, recursivePasteToastMsg, storageFullMessage } from
import helper from '../../lib/helper.js' import helper from '../../lib/helper.js'
import { RemixAppManager } from '../../remixAppManager' import { RemixAppManager } from '../../remixAppManager'
import { commitChange } from '@remix-ui/git' import { commitChange } from '@remix-ui/git'
import { Editor } from '../editor/editor'
import { IEditorFile } from '@remix-ui/editor'
/* /*
attach to files event (removed renamed) attach to files event (removed renamed)
@ -27,7 +25,7 @@ const profile = {
methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'writeMultipleFiles', 'writeFileNoRewrite', methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'writeMultipleFiles', 'writeFileNoRewrite',
'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile',
'getFolder', 'setFile', 'switchFile', 'refresh', 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', 'getFolder', 'setFile', 'switchFile', 'refresh', 'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath',
'saveCurrentFile', 'setBatchFiles', 'isGitRepo', 'isFile', 'isDirectory', 'hasGitSubmodule', 'copyFolderToJson' 'saveCurrentFile', 'setBatchFiles', 'isGitRepo', 'isFile', 'isDirectory', 'hasGitSubmodule', 'copyFolderToJson', 'diff'
], ],
kind: 'file-system' kind: 'file-system'
} }
@ -710,7 +708,6 @@ class FileManager extends Plugin {
this._deps.config.set('currentFile', '') this._deps.config.set('currentFile', '')
// TODO: Only keep `this.emit` (issue#2210) // TODO: Only keep `this.emit` (issue#2210)
this.emit('noFileSelected') this.emit('noFileSelected')
this.events.emit('noFileSelected')
if(!change.readonly){ if(!change.readonly){
let file = this.normalize(change.path) let file = this.normalize(change.path)
@ -722,7 +719,6 @@ class FileManager extends Plugin {
await this.editor.openDiff(change) await this.editor.openDiff(change)
this.emit('openDiff', change) this.emit('openDiff', change)
this.events.emit('openDiff', change)
} }
async closeDiff(change: commitChange) { async closeDiff(change: commitChange) {
@ -733,18 +729,15 @@ class FileManager extends Plugin {
this._deps.config.set('currentFile', '') this._deps.config.set('currentFile', '')
// TODO: Only keep `this.emit` (issue#2210) // TODO: Only keep `this.emit` (issue#2210)
this.emit('noFileSelected') this.emit('noFileSelected')
this.events.emit('noFileSelected')
} }
} }
this.emit('closeDiff', change) this.emit('closeDiff', change)
this.events.emit('closeDiff', change)
} }
async openFile(file?: string) { async openFile(file?: string) {
if (!file) { if (!file) {
this.emit('noFileSelected') this.emit('noFileSelected')
this.events.emit('noFileSelected')
} else { } else {
file = this.normalize(file) file = this.normalize(file)
const resolved = this.getPathFromUrl(file) const resolved = this.getPathFromUrl(file)
@ -780,7 +773,6 @@ class FileManager extends Plugin {
} }
// TODO: Only keep `this.emit` (issue#2210) // TODO: Only keep `this.emit` (issue#2210)
this.emit('currentFileChanged', file) this.emit('currentFileChanged', file)
this.events.emit('currentFileChanged', file)
return true return true
} }
} }

@ -43,6 +43,11 @@ export class Layout extends Plugin {
this.panels.main.active = false this.panels.main.active = false
this.event.emit('change', null) this.event.emit('change', null)
}) })
this.on('fileManager', 'openDiff', () => {
this.panels.editor.active = true
this.panels.main.active = false
this.event.emit('change', null)
})
this.on('tabs', 'openFile', () => { this.on('tabs', 'openFile', () => {
this.panels.editor.active = true this.panels.editor.active = true
this.panels.main.active = false this.panels.main.active = false
@ -59,6 +64,12 @@ export class Layout extends Plugin {
this.panels.main.active = false this.panels.main.active = false
this.event.emit('change', null) this.event.emit('change', null)
}) })
this.on('tabs', 'openDiff', () => {
console.log('openDiff')
this.panels.editor.active = true
this.panels.main.active = false
this.event.emit('change', null)
})
this.on('manager', 'activate', (profile: Profile) => { this.on('manager', 'activate', (profile: Profile) => {
switch (profile.name) { switch (profile.name) {
case 'filePanel': case 'filePanel':

@ -146,6 +146,23 @@ export class TabProxy extends Plugin {
} }
}) })
this.on('fileManager', 'openDiff', (commit) => {
const hash = commit.hashModified? commit.hashModified.substring(0,6): 'Working Tree'
const name = `${commit.path} (${hash})`
this.addTab(name, name, async () => {
await this.fileManager.diff(commit)
this.event.emit('openDiff', commit)
this.emit('openDiff', commit)
},
async () => {
this.removeTab(name)
await this.fileManager.closeDiff(commit)
this.event.emit('closeDiff', commit)
this.emit('closeDiff', commit)
})
this.tabsApi.activateTab(name)
})
this.on('manager', 'pluginActivated', ({ name, location, displayName, icon, description }) => { this.on('manager', 'pluginActivated', ({ name, location, displayName, icon, description }) => {
if (location === 'mainPanel') { if (location === 'mainPanel') {
this.addTab( this.addTab(

@ -1,5 +1,6 @@
import { monacoTypes } from '@remix-ui/editor'; import { monacoTypes } from '@remix-ui/editor';
import { commitChange } from '@remix-ui/git';
export interface Action { export interface Action {
type: string; type: string;
payload: Record<string, any> payload: Record<string, any>
@ -38,6 +39,10 @@ export const reducerActions = (models = initialState, action: Action) => {
delete models[uri] delete models[uri]
return models return models
} }
case 'ADD_DIFF': {
if (!editor) return models
return models
}
case 'SET_VALUE': { case 'SET_VALUE': {
if (!editor) return models if (!editor) return models
const uri = action.payload.uri const uri = action.payload.uri
@ -111,6 +116,15 @@ export const reducerListener = (plugin, dispatch, monaco, editor, events) => {
}) })
}) })
plugin.on('editor', 'addDiff', (value: commitChange) => {
dispatch({
type: 'ADD_DIFF',
payload: { value },
monaco,
editor
})
})
plugin.on('editor', 'disposeModel', (uri) => { plugin.on('editor', 'disposeModel', (uri) => {
dispatch({ dispatch({
type: 'DISPOSE_MODEL', type: 'DISPOSE_MODEL',

@ -1,7 +1,7 @@
import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line
import { FormattedMessage, useIntl } from 'react-intl' import { FormattedMessage, useIntl } from 'react-intl'
import { isArray } from 'lodash' import { isArray } from 'lodash'
import Editor, { loader, Monaco } from '@monaco-editor/react' import Editor, { DiffEditor, loader, Monaco } from '@monaco-editor/react'
import { AlertModal } from '@remix-ui/app' import { AlertModal } from '@remix-ui/app'
import { ConsoleLogs, QueryParams } from '@remix-project/remix-lib' import { ConsoleLogs, QueryParams } from '@remix-project/remix-lib'
import { reducerActions, reducerListener, initialState } from './actions/editor' import { reducerActions, reducerListener, initialState } from './actions/editor'
@ -134,6 +134,8 @@ export interface EditorUIProps {
activated: boolean activated: boolean
themeType: string themeType: string
currentFile: string currentFile: string
currentDiffFile: string
isDiff: boolean
events: { events: {
onBreakPointAdded: (file: string, line: number) => void onBreakPointAdded: (file: string, line: number) => void
onBreakPointCleared: (file: string, line: number) => void onBreakPointCleared: (file: string, line: number) => void
@ -146,6 +148,8 @@ export interface EditorUIProps {
export const EditorUI = (props: EditorUIProps) => { export const EditorUI = (props: EditorUIProps) => {
const intl = useIntl() const intl = useIntl()
const [, setCurrentBreakpoints] = useState({}) const [, setCurrentBreakpoints] = useState({})
const [isDiff, setIsDiff] = useState(false)
const [isSplit, setIsSplit] = useState(true)
const defaultEditorValue = ` const defaultEditorValue = `
\t\t\t\t\t\t\t ____ _____ __ __ ___ __ __ ___ ____ _____ \t\t\t\t\t\t\t ____ _____ __ __ ___ __ __ ___ ____ _____
\t\t\t\t\t\t\t| _ \\ | ____| | \\/ | |_ _| \\ \\/ / |_ _| | _ \\ | ____| \t\t\t\t\t\t\t| _ \\ | ____| | \\/ | |_ _| \\ \\/ / |_ _| | _ \\ | ____|
@ -170,6 +174,8 @@ export const EditorUI = (props: EditorUIProps) => {
const pasteCodeRef = useRef(false) const pasteCodeRef = useRef(false)
const editorRef = useRef(null) const editorRef = useRef(null)
const monacoRef = useRef<Monaco>(null) const monacoRef = useRef<Monaco>(null)
const diffEditorRef = useRef<any>(null)
const currentFunction = useRef('') const currentFunction = useRef('')
const currentFileRef = useRef('') const currentFileRef = useRef('')
const currentUrlRef = useRef('') const currentUrlRef = useRef('')
@ -325,11 +331,20 @@ export const EditorUI = (props: EditorUIProps) => {
}) })
useEffect(() => { useEffect(() => {
if (!editorRef.current || !props.currentFile) return console.log(props.isDiff, props.currentFile)
if (!(editorRef.current || diffEditorRef.current ) || !props.currentFile) return
currentFileRef.current = props.currentFile currentFileRef.current = props.currentFile
props.plugin.call('fileManager', 'getUrlFromPath', currentFileRef.current).then((url) => (currentUrlRef.current = url.file)) props.plugin.call('fileManager', 'getUrlFromPath', currentFileRef.current).then((url) => (currentUrlRef.current = url.file))
const file = editorModelsState[props.currentFile] const file = editorModelsState[props.currentFile]
props.isDiff && diffEditorRef && diffEditorRef.current && diffEditorRef.current.setModel({
original: editorModelsState[props.currentDiffFile].model,
modified: file.model
})
props.isDiff && diffEditorRef.current.getModifiedEditor().updateOptions({ readOnly: editorModelsState[props.currentFile].readOnly })
editorRef.current.setModel(file.model) editorRef.current.setModel(file.model)
editorRef.current.updateOptions({ editorRef.current.updateOptions({
readOnly: editorModelsState[props.currentFile].readOnly, readOnly: editorModelsState[props.currentFile].readOnly,
@ -345,7 +360,7 @@ export const EditorUI = (props: EditorUIProps) => {
} else if (file.language === 'circom') { } else if (file.language === 'circom') {
monacoRef.current.editor.setModelLanguage(file.model, 'remix-circom') monacoRef.current.editor.setModelLanguage(file.model, 'remix-circom')
} }
}, [props.currentFile]) }, [props.currentFile, props.isDiff])
const convertToMonacoDecoration = (decoration: lineText | sourceAnnotation | sourceMarker, typeOfDecoration: string) => { const convertToMonacoDecoration = (decoration: lineText | sourceAnnotation | sourceMarker, typeOfDecoration: string) => {
if (typeOfDecoration === 'sourceAnnotationsPerFile') { if (typeOfDecoration === 'sourceAnnotationsPerFile') {
@ -611,6 +626,14 @@ export const EditorUI = (props: EditorUIProps) => {
} }
} }
function handleDiffEditorDidMount(editor: any) {
console.log('diff editor mounted')
diffEditorRef.current = editor
defineAndSetTheme(monacoRef.current)
reducerListener(props.plugin, dispatch, monacoRef.current, diffEditorRef.current.getModifiedEditor(), props.events)
props.events.onEditorMounted()
}
function handleEditorDidMount(editor) { function handleEditorDidMount(editor) {
editorRef.current = editor editorRef.current = editor
defineAndSetTheme(monacoRef.current) defineAndSetTheme(monacoRef.current)
@ -923,8 +946,22 @@ export const EditorUI = (props: EditorUIProps) => {
return ( return (
<div className="w-100 h-100 d-flex flex-column-reverse"> <div className="w-100 h-100 d-flex flex-column-reverse">
<DiffEditor
originalLanguage={'remix-solidity'}
modifiedLanguage={'remix-solidity'}
original={''}
modified={''}
onMount={handleDiffEditorDidMount}
beforeMount={handleEditorWillMount}
options={{ readOnly: false, renderSideBySide: isSplit }}
width='100%'
height={props.isDiff ? '100%' : '0%'}
className={props.isDiff ? "d-block" : "d-none"}
/>
<Editor <Editor
width="100%" width="100%"
height={props.isDiff ? '0%' : '100%'}
path={props.currentFile} path={props.currentFile}
language={editorModelsState[props.currentFile] ? editorModelsState[props.currentFile].language : 'text'} language={editorModelsState[props.currentFile] ? editorModelsState[props.currentFile].language : 'text'}
onMount={handleEditorDidMount} onMount={handleEditorDidMount}
@ -937,6 +974,7 @@ export const EditorUI = (props: EditorUIProps) => {
} }
}} }}
defaultValue={defaultEditorValue} defaultValue={defaultEditorValue}
className={props.isDiff ? "d-none" : "d-block"}
/> />
{editorModelsState[props.currentFile]?.readOnly && ( {editorModelsState[props.currentFile]?.readOnly && (
<span className="pl-4 h6 mb-0 w-100 alert-info position-absolute bottom-0 end-0"> <span className="pl-4 h6 mb-0 w-100 alert-info position-absolute bottom-0 end-0">

@ -745,11 +745,15 @@ export const diff = async (commitChange: commitChange) => {
export const getCommitChanges = async (oid1: string, oid2: string, branch?: branch, remote?: remote) => { export const getCommitChanges = async (oid1: string, oid2: string, branch?: branch, remote?: remote) => {
console.log(oid1, oid2, branch, remote) console.log(oid1, oid2, branch, remote)
try {
let log
try { try {
// check if oid2 exists // check if oid2 exists
const log = await plugin.call('dGitProvider', 'log', { log = await plugin.call('dGitProvider', 'log', {
ref: branch ? branch.name : 'HEAD', ref: branch ? branch.name : 'HEAD',
}) })
} catch (e) {
}
if (log) { if (log) {
const foundCommit = log.find((commit: ReadCommitResult) => commit.oid === oid2) const foundCommit = log.find((commit: ReadCommitResult) => commit.oid === oid2)
if (!foundCommit) { if (!foundCommit) {

Loading…
Cancel
Save