From 43e55a963bef2a2e4740ce27d456927b020b71f2 Mon Sep 17 00:00:00 2001 From: August Skare Date: Thu, 25 Oct 2018 12:19:56 +0100 Subject: Feature/syntaxhighlighting (#9) * wip code highlighting of lines * Implements gutter component * WIP: Profiler with gutter * cleaned up highlight code * Removes before content for gutter styling * Styles gutter * Add correct Profiler code content * Adds color variable for gutter gray * refactor code component width gutter and diffing --- packages/dev-tools-pages/package.json | 1 - packages/dev-tools-pages/ts/components/Code.tsx | 106 ++++++++++++++++------- packages/dev-tools-pages/ts/components/Intro.tsx | 1 + packages/dev-tools-pages/ts/highlight.tsx | 47 +++++++++- packages/dev-tools-pages/ts/pages/Cov.tsx | 30 ++++--- packages/dev-tools-pages/ts/pages/Profiler.tsx | 25 +++++- packages/dev-tools-pages/ts/variables.tsx | 1 + 7 files changed, 159 insertions(+), 52 deletions(-) (limited to 'packages/dev-tools-pages') diff --git a/packages/dev-tools-pages/package.json b/packages/dev-tools-pages/package.json index c85ff44a6..eb34e3715 100644 --- a/packages/dev-tools-pages/package.json +++ b/packages/dev-tools-pages/package.json @@ -18,7 +18,6 @@ "dependencies": { "@0xproject/react-shared": "^1.0.15", "highlight.js": "^9.13.1", - "highlighter": "^0.1.0", "less": "^2.7.2", "polished": "^1.9.2", "react": "^16.5.2", diff --git a/packages/dev-tools-pages/ts/components/Code.tsx b/packages/dev-tools-pages/ts/components/Code.tsx index 5a03e79ac..ce4443357 100644 --- a/packages/dev-tools-pages/ts/components/Code.tsx +++ b/packages/dev-tools-pages/ts/components/Code.tsx @@ -4,12 +4,13 @@ import styled from 'styled-components'; import { colors } from 'ts/variables'; import BaseButton from './Button'; -var highlight = require('highlighter')(); - interface CodeProps { children: React.ReactNode; language?: string; light?: boolean; + diff?: boolean; + gutter?: Array; + gutterLength?: number; } interface CodeState { @@ -30,37 +31,73 @@ const Button = styled(BaseButton)` const Base = styled.div < - CodeProps > - ` + CodeProps > + ` color: ${props => (props.language === undefined ? colors.white : 'inherit')}; background-color: ${props => - props.light ? 'rgba(255,255,255,.15)' : props.language === undefined ? colors.black : colors.lightGray}; + props.light ? 'rgba(255,255,255,.15)' : props.language === undefined ? colors.black : '#F1F4F5'}; white-space: ${props => (props.language === undefined ? 'nowrap' : '')}; position: relative; + + ${props => + props.diff + ? ` + background-color: #E9ECED; + display: flex; + padding-top: 1.5rem; + padding-bottom: 1.5rem; + ` + : ` + padding: 1.5rem; + `} + + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + &:hover ${Button} { opacity: 1; } `; -const StyledCode = styled.code` - padding-top: 1.5rem; - padding-bottom: 1.5rem; - display: block; - overflow-y: scroll; - -webkit-overflow-scrolling: touch; +const StyledCodeDiff = + styled.code < + any > + ` + ::before { + content: ''; + width: calc(.75rem + ${props => props.gutterLength}ch); + background-color: #e2e5e6; + position: absolute; + top: 0; + left: 0; + bottom: 0; + } - - .diff-addition { - background-color: #d2e9e0; - padding: 0.3125rem; + [class^='line-'] { display: inline-block; width: 100%; + position: relative; + padding-right: 1.5rem; + padding-left: calc(2.25rem + ${props => props.gutterLength}ch); + ::before { + content: attr(data-test); + font-size: 0.875rem; + width: ${props => props.gutterLength}; + padding-left: .375rem; + padding-right: .375rem; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + z-index: 1; + } } - .diff-deletion { - background-color: #ebdcdc; - padding: 0.3125rem; - display: inline-block; - width: 100%; + + .line-addition { + background-color: rgba(0, 202, 105, 0.1); + } + .line-deletion { + background-color: rgba(255, 0, 0, 0.07); } `; @@ -88,13 +125,16 @@ class Code extends React.Component { } async componentDidMount() { - const { language, children } = this.props; + const { language, children, diff, gutter } = this.props; + + const code = children as string; if (language !== undefined) { - const { default: hljs } = await System.import(/* webpackChunkName: 'highlightjs' */ 'ts/highlight'); + const { default: highlight } = await System.import(/* webpackChunkName: 'highlightjs' */ 'ts/highlight'); - const hlCode = hljs(children as string, language); - this.setState({ hlCode }); + this.setState({ + hlCode: highlight(language, code, diff, gutter), + }); } } @@ -115,16 +155,20 @@ class Code extends React.Component { }; render() { - const { language, light, children } = this.props; + const { language, light, diff, children, gutterLength } = this.props; + const { hlCode } = this.state; + + const Code = diff ? StyledCodeDiff : 'code'; return ( - + - {this.state.hlCode !== undefined ? ( - - ) : ( - {this.props.children} - )} + + {hlCode === undefined ? children : null} + {navigator.userAgent !== 'ReactSnap' ? : null} {!('clipboard' in navigator) ? ( diff --git a/packages/dev-tools-pages/ts/components/Intro.tsx b/packages/dev-tools-pages/ts/components/Intro.tsx index 4fc1289fb..e5c95d4c2 100644 --- a/packages/dev-tools-pages/ts/components/Intro.tsx +++ b/packages/dev-tools-pages/ts/components/Intro.tsx @@ -43,6 +43,7 @@ const IntroLead = styled(Lead)` `; const IntroAside = styled.div` max-width: 32.5rem; + position: relative; ${media.small` margin-left: -30px; diff --git a/packages/dev-tools-pages/ts/highlight.tsx b/packages/dev-tools-pages/ts/highlight.tsx index 9d7844c89..7187118d0 100644 --- a/packages/dev-tools-pages/ts/highlight.tsx +++ b/packages/dev-tools-pages/ts/highlight.tsx @@ -1,8 +1,47 @@ -const highlight = require('highlight.js/lib/highlight'); +const hljs = require('highlight.js/lib/highlight'); const javascript = require('highlight.js/lib/languages/javascript'); -const json = require('highlight.js/lib/languages/json'); -highlight.registerLanguage('javascript', javascript); -highlight.registerLanguage('json', json); +hljs.registerLanguage('javascript', javascript); + +interface PatchInterface { + [key: string]: string; +} + +var PATCH_TYPES: PatchInterface = { + '+': 'addition', + '-': 'deletion', + '!': 'change', +}; + +function diffHighlight(language: string, code: any, gutter: any) { + return code + .split(/\r?\n/g) + .map((line: string, index: number) => { + var type; + if (/^-{3} [^-]+ -{4}$|^\*{3} [^*]+ \*{4}$|^@@ [^@]+ @@$/.test(line)) { + type = 'chunk'; + } else if (/^Index: |^[+\-*]{3}|^[*=]{5,}$/.test(line)) { + type = 'header'; + } else { + type = PATCH_TYPES[line[0] as string] || 'null'; + line = line.replace(/^[+\-! ]/, ''); + } + + const g = gutter[index]; + + return `${ + hljs.highlight(language, line).value + }`; + }) + .join('\n'); +} + +function highlight(language: string, code: string, diff: boolean, gutter: any) { + if (diff) { + return diffHighlight(language, code, gutter); + } + + return hljs.highlight(language, code).value; +} export default highlight; diff --git a/packages/dev-tools-pages/ts/pages/Cov.tsx b/packages/dev-tools-pages/ts/pages/Cov.tsx index 01966537c..197ff174d 100644 --- a/packages/dev-tools-pages/ts/pages/Cov.tsx +++ b/packages/dev-tools-pages/ts/pages/Cov.tsx @@ -22,19 +22,25 @@ function Cov() { coverage. - + {`+function executeTransaction(uint transactionId) - public -+notExecuted(transactionId) -+pastTimeLock(transactionId) + public ++ notExecuted(transactionId) ++ fullyConfirmed(transactionId) ++ pastTimeLock(transactionId) { -+Transaction storage tx = transactions[transactionId] -+tx.executed = true -+if (tx.destination.call.value(tx.value)(tx.data)) -+Execution(transactionId) -else { --ExecutionFailure(transactionId) - ++ Transaction storage tx = transactions[transactionId] ++ tx.executed = true ++ if (tx.destination.call.value(tx.value)(tx.data)) ++ Execution(transactionId) + else { +- ExecutionFailure(transactionId) +- tx.executed = false } }`} @@ -69,7 +75,7 @@ else { - + {`import { SolCompilerArtifactAdapter } from '@0x/sol-trace'; // Both artifactsDir and contractsDir are optional and will be fetched from compiler.json if not passed in diff --git a/packages/dev-tools-pages/ts/pages/Profiler.tsx b/packages/dev-tools-pages/ts/pages/Profiler.tsx index ac88bd933..462789a16 100644 --- a/packages/dev-tools-pages/ts/pages/Profiler.tsx +++ b/packages/dev-tools-pages/ts/pages/Profiler.tsx @@ -9,18 +9,35 @@ import { Tabs, TabBlock } from 'ts/components/Tabs'; import Code from 'ts/components/Code'; import InlineCode from 'ts/components/InlineCode'; import { List, ListItem } from 'ts/components/List'; -import Intro from 'ts/components/Intro'; import Breakout from 'ts/components/Breakout'; +import { Intro, IntroLead, IntroAside } from 'ts/components/Intro'; function Profiler() { return ( - -

+ + Sol-profiler gathers line-by-line gas usage for any transaction submitted through your provider. This will help you find unexpected inefficiencies in parts of your smart contract, and take a data-driven approach to optimizing it. -

+ + + + {`+function() public payable { ++ deposit(); +} ++function deposit() public payabble { ++ balanceOf[msg.sender] += msg.value; ++ Deposit(msg.sender, msg.value); +} +-function withdraw(uint wad) public { +- require(balanceOf[msg.sender] >= wad); +- balanceOf[msg.sender] -= wad; +- msg.sender.transfer(wad); +- Withdrawal(msg.sender, wad); +}`} + +
diff --git a/packages/dev-tools-pages/ts/variables.tsx b/packages/dev-tools-pages/ts/variables.tsx index 8f08d13eb..76a675546 100644 --- a/packages/dev-tools-pages/ts/variables.tsx +++ b/packages/dev-tools-pages/ts/variables.tsx @@ -6,6 +6,7 @@ const colors = { lightGray: '#F1F4F5', gray: '#F1F2F7', darkGray: '#E9ECED', + darkestGray: '#E2E5E6', blueGray: '#ECEFF9', }; -- cgit v1.2.3