Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ Improved Go Playground powered by Monaco Editor and React

* 💡 Code autocomplete
* 💾 Load and save files
* 🛠 [WebAssembly](https://github.com/golang/go/wiki/WebAssembly) support (see [latest release notes](https://github.com/x1unix/go-playground/releases/tag/v1.3.0))
* 📔 Snippets and tutorials
* 🛠 [WebAssembly](https://github.com/golang/go/wiki/WebAssembly) support
* 🌚 Dark theme


And more

## Demo

[http://goplay.x1unix.com/](http://goplay.x1unix.com/)
[http://goplay.tools/](goplay.tools)

## Installation

Expand All @@ -40,6 +41,13 @@ $ ./playground -f ./data/packages.json -debug

Use `-help` to get information about command params

### Third-party credits

* Default playground run server provided by [play.golang.org](https://play.golang.org)
* Code for templates and tutorials provided by [gobyexample.com](https://gobyexample.com/)
* Code completion snippets were inspired by [tj/vscode-snippets](https://github.com/tj/vscode-snippets/blob/master/go.json)


## Contributors

### Code Contributors
Expand Down
6 changes: 3 additions & 3 deletions build/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ ARG GITHUB_URL=https://github.com/x1unix/go-playground
RUN yarn install --silent && \
REACT_APP_VERSION=$APP_VERSION REACT_APP_GITHUB_URL=$GITHUB_URL REACT_APP_GTAG=$APP_GTAG yarn build

FROM golang:1.13-alpine as build
FROM golang:1.14-alpine as build
WORKDIR /tmp/playground
COPY cmd ./cmd
COPY pkg ./pkg
COPY go.mod .
COPY go.sum .
RUN go build -o server ./cmd/playground && \
RUN go build -o server -ldflags="-X 'main.Version=$APP_VERSION'" ./cmd/playground && \
GOOS=js GOARCH=wasm go build -o ./worker.wasm ./cmd/webworker && \
cp $(go env GOROOT)/misc/wasm/wasm_exec.js .

FROM golang:1.13-alpine as production
FROM golang:1.14-alpine as production
WORKDIR /opt/playground
ENV GOROOT /usr/local/go
ENV APP_CLEAN_INTERVAL=10m
Expand Down
5 changes: 4 additions & 1 deletion cmd/playground/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"go.uber.org/zap"
)

const Version = "testing"

type appArgs struct {
packagesFile string
addr string
Expand Down Expand Up @@ -75,6 +77,7 @@ func start(goRoot string, args appArgs) error {
return fmt.Errorf("invalid cleanup interval parameter: %s", err)
}

zap.S().Info("Server version: ", Version)
zap.S().Infof("GOROOT is %q", goRoot)
zap.S().Infof("Packages file is %q", args.packagesFile)
zap.S().Infof("Cleanup interval is %s", cleanInterval.String())
Expand All @@ -94,7 +97,7 @@ func start(goRoot string, args appArgs) error {
go store.StartCleaner(ctx, cleanInterval, nil)

r := mux.NewRouter()
langserver.New(packages, compiler.NewBuildService(zap.S(), store)).
langserver.New(Version, packages, compiler.NewBuildService(zap.S(), store)).
Mount(r.PathPrefix("/api").Subrouter())
r.PathPrefix("/").Handler(langserver.SpaFileServer("./public"))

Expand Down
7 changes: 7 additions & 0 deletions pkg/analyzer/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ func (p *Package) SymbolByChar(chr string) []*CompletionItem {
return append(p.Functions.Match(chr), result...)
}

func (p *Package) AllSymbols() []*CompletionItem {
out := make([]*CompletionItem, 0, p.Values.Len()+p.Functions.Len())
out = append(out, p.Functions.Symbols...)
out = append(out, p.Values.Symbols...)
return out
}

func (p *Package) GetCompletionItem() *CompletionItem {
return &CompletionItem{
Label: p.Name,
Expand Down
4 changes: 4 additions & 0 deletions pkg/analyzer/sym_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ type SymbolIndex struct {
charMap map[string][]*CompletionItem
}

func (si *SymbolIndex) Len() int {
return len(si.Symbols)
}

func emptySymbolIndex() SymbolIndex {
return SymbolIndex{
Symbols: []*CompletionItem{},
Expand Down
8 changes: 8 additions & 0 deletions pkg/langserver/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ func (r *ErrorResponse) Write(w http.ResponseWriter) http.ResponseWriter {
return w
}

type VersionResponse struct {
Version string `json:"version"`
}

func (r VersionResponse) Write(w http.ResponseWriter) {
WriteJSON(w, r)
}

type SuggestionsResponse struct {
Suggestions []*analyzer.CompletionItem `json:"suggestions"`
}
Expand Down
28 changes: 22 additions & 6 deletions pkg/langserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,17 @@ const (
)

type Service struct {
version string
log *zap.SugaredLogger
index analyzer.PackageIndex
compiler compiler.BuildService
limiter *rate.Limiter
}

func New(packages []*analyzer.Package, builder compiler.BuildService) *Service {
func New(version string, packages []*analyzer.Package, builder compiler.BuildService) *Service {
return &Service{
compiler: builder,
version: version,
log: zap.S().Named("langserver"),
index: analyzer.BuildPackageIndex(packages),
limiter: rate.NewLimiter(rate.Every(frameTime), compileRequestsPerFrame),
Expand All @@ -46,6 +48,8 @@ func New(packages []*analyzer.Package, builder compiler.BuildService) *Service {

// Mount mounts service on route
func (s *Service) Mount(r *mux.Router) {
r.Path("/version").
HandlerFunc(WrapHandler(s.HandleGetVersion))
r.Path("/suggest").
HandlerFunc(WrapHandler(s.HandleGetSuggestion))
r.Path("/run").Methods(http.MethodPost).
Expand Down Expand Up @@ -83,10 +87,6 @@ func (s *Service) lookupBuiltin(val string) (*SuggestionsResponse, error) {
}

func (s *Service) provideSuggestion(req SuggestionRequest) (*SuggestionsResponse, error) {
if req.Value == "" {
return nil, fmt.Errorf("empty suggestion request value, nothing to provide")
}

// Provide package suggestions (if requested)
if req.PackageName != "" {
pkg, ok := s.index.PackageByName(req.PackageName)
Expand All @@ -98,14 +98,30 @@ func (s *Service) provideSuggestion(req SuggestionRequest) (*SuggestionsResponse
return nil, fmt.Errorf("failed to analyze package %q: %s", req.PackageName, err)
}

var symbols []*analyzer.CompletionItem
if req.Value != "" {
symbols = pkg.SymbolByChar(req.Value)
} else {
symbols = pkg.AllSymbols()
}

return &SuggestionsResponse{
Suggestions: pkg.SymbolByChar(req.Value),
Suggestions: symbols,
}, nil
}

if req.Value == "" {
return nil, fmt.Errorf("empty suggestion request value, nothing to provide")
}

return s.lookupBuiltin(req.Value)
}

func (s *Service) HandleGetVersion(w http.ResponseWriter, r *http.Request) error {
WriteJSON(w, VersionResponse{Version: s.version})
return nil
}

func (s *Service) HandleGetSuggestion(w http.ResponseWriter, r *http.Request) error {
q := r.URL.Query()
value := q.Get("value")
Expand Down
10 changes: 5 additions & 5 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
"circular-dependency-plugin": "^5.2.0",
"connected-react-router": "^6.6.1",
"file-saver": "^2.0.2",
"monaco-editor": "^0.19.3",
"monaco-editor-webpack-plugin": "^1.8.2",
"monaco-editor": "^0.20.0",
"monaco-editor-webpack-plugin": "^1.9.0",
"office-ui-fabric-react": "^7.82.1",
"react": "^16.12.0",
"react-app-rewired": "^2.1.5",
"react-dom": "^16.12.0",
"react-monaco-editor": "^0.33.0",
"react-monaco-editor": "^0.39.1",
"react-redux": "^7.1.3",
"react-router-dom": "^5.1.2",
"react-scripts": "3.3.0",
Expand All @@ -26,8 +26,8 @@
"uuid": "^3.4.0"
},
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"start": "GENERATE_SOURCEMAP=true react-app-rewired start",
"build": "GENERATE_SOURCEMAP=false react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject",
"gen:suggestions": "node ./src/editor/internal/genpkgcache.js"
Expand Down
Binary file added web/public/fonts/CascadiaCode.ttf
Binary file not shown.
Binary file added web/public/fonts/FiraCode-Bold.ttf
Binary file not shown.
Binary file added web/public/fonts/FiraCode-Medium.ttf
Binary file not shown.
Binary file added web/public/fonts/FiraCode-Regular.ttf
Binary file not shown.
Binary file added web/public/fonts/FiraCode-Retina.ttf
Binary file not shown.
Binary file added web/public/fonts/FiraCode-SemiBold.ttf
Binary file not shown.
Binary file added web/public/fonts/JetBrainsMono-Bold.ttf
Binary file not shown.
Binary file added web/public/fonts/JetBrainsMono-Medium.ttf
Binary file not shown.
Binary file added web/public/fonts/JetBrainsMono-Regular.ttf
Binary file not shown.
80 changes: 80 additions & 0 deletions web/src/ChangeLogModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from 'react';
import { Modal } from 'office-ui-fabric-react/lib/Modal';
import { Link } from 'office-ui-fabric-react/lib/Link';
import {getTheme, IconButton } from 'office-ui-fabric-react';
import {getContentStyles, getIconButtonStyles} from './styles/modal';
import config from './services/config';

const TITLE_ID = 'ChangeLogTitle';
const SUB_TITLE_ID = 'ChangeLogSubtitle';

interface ChangeLogModalProps {
isOpen: boolean
onClose: () => void
}

export default function ChangeLogModal(props: ChangeLogModalProps) {
const theme = getTheme();
const contentStyles = getContentStyles(theme);
const iconButtonStyles = getIconButtonStyles(theme);

return (
<Modal
titleAriaId={TITLE_ID}
subtitleAriaId={SUB_TITLE_ID}
isOpen={props.isOpen}
onDismiss={props.onClose}
containerClassName={contentStyles.container}
>
<div className={contentStyles.header}>
<span id={TITLE_ID}>Changelog for {config.appVersion}</span>
<IconButton
iconProps={{ iconName: 'Cancel' }}
styles={iconButtonStyles}
ariaLabel='Close popup modal'
onClick={props.onClose as any}
/>
</div>
<div id={SUB_TITLE_ID} className={contentStyles.body}>
<p>
<b>Interface - Global</b>
<ul>
<li>Added list of snippets with <u>templates and tutorials</u> near <b>Open</b> menu item</li>
<li>Moved <b>Settings</b> menu button from drop-down to main section</li>
</ul>
</p>
<p>
<b>Interface - Settings</b>
<ul>
<li>Added editor fonts selector</li>
<li>Added support of font code ligatures</li>
<li>Fixed fallback font issue that might cause issues on Linux</li>
</ul>
</p>
<p>
<b>Interface - Editor</b>
<ul>
<li>
Added code snippets to make code input faster:
<ul>
<li><code>iferr</code> - Error handling snippet</li>
<li><code>switch</code> - Quick switch declaration</li>
<li><code>typestruct</code> - Quickly declare struct</li>
<li><code>fmtprintf</code> - fmt.Printf shorthand</li>
<li>and other (see release notes)</li>
</ul>
</li>
</ul>
</p>
<p>
And more!
</p>
<p>
Full release notes for are available <Link href={`${config.githubUrl}/releases/latest`} target='_blank'>here</Link>
</p>
</div>
</Modal>
)
}

ChangeLogModal.defaultProps = {isOpen: false};
15 changes: 15 additions & 0 deletions web/src/Header.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@
min-height: 44px;
}

.app__update {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
max-width: 500px;
z-index: 9999;
}

.app__update.app__update--visible {
display: block
}

.header__preloader {
margin-right: 15px;
}
Expand Down
Loading