elves / elvish Goto Github PK
View Code? Open in Web Editor NEWPowerful scripting language & versatile interactive shell
Home Page: https://elv.sh/
License: BSD 2-Clause "Simplified" License
Powerful scripting language & versatile interactive shell
Home Page: https://elv.sh/
License: BSD 2-Clause "Simplified" License
This note evaluates the viability of meta-characters, namely characters that are part of the syntax. Each is given a score along with the reasons, either historical or practical. Well-known uses in POSIX sh
are always given a score of +5; other scores are determined case by case.
~
+5
$HOME
at beginning of a word (+5)#
+5
$
+5
&
+5
*
+5
?
+5
<
>
+5
"
+5
'
+5
- sh: command substitution (+5)
|
+5
\
+5
;
+5
{
}
+5
[
]
+4
^
+4
!
+2
%
+1
(
)
+1
@
-2
+
-2
+option
(-2):
-3
,
-3
--option-key=v1,v2
.
-5
a.out
/
-5
/path/to/file
=
-5
--option-key=value
(-5)-
-5
_
-5
file_names
(-5)Elvish currently lacks a static typing system. The basics could be taken from Typed Racket.
Some points:
Open questions:
Cool project. I tried to build it but I'm getting errors:
$ go get github.com/xiaq/elvish
# github.com/xiaq/elvish/edit/tty
dev/go/src/github.com/xiaq/elvish/edit/tty/termios.go:20: undefined: syscall.TCGETS
dev/go/src/github.com/xiaq/elvish/edit/tty/termios.go:24: undefined: syscall.TCSETS
dev/go/src/github.com/xiaq/elvish/edit/tty/termios.go:49: cannot use &term.Lflag (type *uint64) as type *uint32 in argument to setFlag
dev/go/src/github.com/xiaq/elvish/edit/tty/termios.go:53: cannot use &term.Lflag (type *uint64) as type *uint32 in argument to setFlag
# github.com/xiaq/elvish/sys
dev/go/src/github.com/xiaq/elvish/sys/select.go:66: not enough arguments to return
Sigils are characters that are only special at the beginning of a compound expression. In less accurate words, a sigil can be followed by a string literal, but cannot break a string literal apart.
In zsh for instance, =
is a sigil. ls =sh
expands to something like ls /bin/sh
, but the =
in ls a=b
is taken as part of the bareword. However, $
is not a sigil, since it is special in ls $b
as well as in ls a$b
.
I'd like to have a general sigil mechanism in Elvish. Some rules for it are:
=!%?*\
.echo =
.ls =sh
is exactly equivalent as ls (= sh)
, where =
could be defined by the user.=
for path expansion and !
for history expansion.\
, which is akin to /
used in regular expressions, as a sigil for that.Command line history is a traditionally essential functionality of the shell UI. Elvish now has a per-session, in-memory command line history, but no persistent history yet.
Despite of the apparent simplicity, there is a particularly annoying issue about command line history - how multiple parallel shell sessions should interact with the persistent history and with each other. See http://zsh.sourceforge.net/Doc/Release/Options.html#History for zsh's struggles on this issue. Like always, the zsh way is to implements all (suboptimal) solutions to the problem and let the user choose...
A shell is interactive. It would be better if one could not only run code, but also develop code from the shell.
The idea of such a system originates from Smalltalk and is recently re-popularized by LightTable. Some ideas could be stolen from them; however, coming up with a natural TUI for that could be a little challenging.
This issue only keeps track of the early designing phase. Once a prototypical implementation is pushed, this issue should be closed.
Related to #1.
On ArchLinux 64 using either go get or the ArchLinux package, if I type the readme example:
~> + 1 2
I get
<tty 1>:1:1: error: pipeline output not satisfiable
It happens in xterm or a virtual terminal. Another minor issue is (not sure if a bug) that if I try to backspace, I get:
Unbound: Ctrl-H
Record mode is a simple way to save part of an interactive session into a script. Like MS office macros, or Vim's recording with q
.
Hit ^R to start and stop recording:
~> ^R
RECORD 1 ~> var $a String
RECORD 2 ~> set $a = `lala`
RECORD 3 ~> echo $a
lala
RECORD 4 ~> ^R
save as (^C for discard): a.elv
(Some style could be applied to RECORD #
)
Currently ports are only exposed to the user via command redirections. It would be nice if they are also available as first-class values.
Preliminary ideas about the syntax:
Add a new builtin special form open
which outputs a port value that would result from applying the redirections it is supplied with. For instance:
var $f = (open >/dev/null)
is roughly equivalent to the following in Python:
f = open('/dev/null', 'w')
Using the value is the same as command redirection:
var $f = (open >/dev/null)
ls >$f
Open questions:
open
behave when supplied with multiple redirections?>
) appears twice. Should we try to eliminate this reduplication?Currently use
simply finds the module file relative to the current directory; a more elaborate algorithm is needed:
./
or ../
, it is relative to the directory of the source file currently being evaluated, or the current directory when evaluated interactively;~/.elvish
.Elvish should source a rc file on an interactive startup.
The current closure syntax {|arg| command}
is modeled after ruby blocks. There are two things I don't like about it:
{echo}
is a list, but { echo}
is a closure. This is too subtle. We can make the argument list (along with the bars) compulsory, but {|| echo} isn't too nice either.fn
; fn f a b c { command }
is equivalent to fn f {|a b c| command}
since I find the latter unnatural. It would be better if we can separate the argument list from the body more clearly.http://rigaux.org/language-study/syntax-across-languages.html#FnctnnnmsFnct collects the syntax for anonymous functions in other languages.
The Emacs shell mode pseudo-tty has really limited capability. For one thing, it does not implement the TIOCGWINSZ ioctl call properly, which is used is query the window size. Instead of the actual window size it always indicates a width of 0 and a height of 0.
The line editor of Elvish in its currently form is essentially a full-screen application comparable to Vim and thus relies heavily on the availability of the window dimension information and cursor movement control codes.
Some kind of line-oriented (instead of screen-oriented) "fallback mode" of the line editor is needed for it to function properly under Emacs shell mode.
You can't get suggestions cd after the first folder.
I should be able to type cd and a few letters then tab to complete that folder and then type a few letters and tab to complete the sub folder.
In the readme the clojure example is used to show how piping makes it more clear.
(require ['clojure.string :refer '(upper-case)])
(def strs '("aha" "LOLaha" "hahaLOL" "hum?"))
(def lols (sort (map upper-case
(filter #(re-find #"LOL" %) strs))))
However, the idiomatic way to express this in Clojure would be using the thread-last macro ->>
which uses the result of each successive expression as the last argument for the next expression.
(def lols (->> strs (filter #(re-find #"LOL" %)) (map upper-case) sort))
Which is conceptually similar to piping, albeit with a few more parentheses.
Under the heading "Pipeline, the Good":
First it is said that concatenative programming is (commonly) a form of functional programming:
So what's concatenative programming? In some of its most common use cases, we can say it's just functional programming without lots of irritating superfluous parentheses.
But later, concatenative programming is contrasted with functional programming, seemingly implying that concatenative programming is not functional programming:
is formed by concatenating simpler programs, hence the term "concatenative programming". Compare this to the functional approach, where constructs are nested instead of connected one after another.
Instead, something else could be written, in order to maintain consistency:
etc.
Namespaces are containers of variables. There are some predefined namespaces, and by importing modules additional namespaces may be introduced.
Modules are self-contained code units that facilitate code reusing. In particular, shell plugins are modules.
As of 74e3db4, nothing of the namespace or module system has been implemented. This issue only keeps track of the early designing phase. Once a prototypical implementation is pushed, this issue should be closed.
Hi. When writing commands, I use to type Ctrl+C
to "reset" and start writing another command (not sure if this is a bad habit xD).
I know of Ctrl+W
for deleting a whole word, but after writing a tar
command with a filename containing a lot of spaces (example), Ctrl+C
is faster than Ctrl+W
.
Well, when I type Ctrl+C
in elvish, this is what happens:
Order of events:
^C
Enter
= "Editor error"... blah. After this error everything works fine...Enter
. I could write a command and it would work.Ctrl+D
) and return to a bash shell, pressing Enter
doesn't move the cursor to the new line; instead, the prompt is written inline.I'm running Go v1.3 in a 64-bit Ubuntu 14.04.
[max:~]$ elvish
~> cd projects
~/projects> ls Test max@maxs-mbp
Completing Test
Test1 Test2 Test3
Editor error: write /dev/stdin: resource temporarily unavailable
My pid is 5341
~/projects>
The Evaler contains mutable states, most notably the local scope, IO ports and the failure handler. Sometimes things needs to be evaluated with a different set of states, possibly asynchronously. The current solution is to fork the Evaler at such circumstances - copy the evaluator, change states as needed, and do the evaluation on the forked Evaler. To summarize, forking happens with
each
and if
), since in that case the forking with form evaluation does not happen. This is a consequence of 3.Evaler forking, though working well for the moment, presents subtle problems (4 for example took a little time to figure out). It also introduces quite some copying, which may or may not be a problem later. Perhaps we can make the mutable states more explicit and somehow separate them from the (mostly) immutable parts of the Evaler.
Minimal case:
* (+ 3 4) 7
Likely some bug in the harvesting of command exit codes.
While trying examples from the README, I found that the following line causes a panic with go1.3:
philip@indiana:~$ elvish
~> println [a b c &key value][key]
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x30 pc=0x4609ed]
goroutine 92 [running]:
runtime.panic(0x530940, 0x80d6b3)
/home/philip/projects/f/go/src/pkg/runtime/panic.c:279 +0xf5
github.com/xiaq/elvish/eval.print(0xc20803b320, 0xc20804f360, 0x2, 0x2, 0x0, 0x0)
/home/philip/projects/go/src/github.com/xiaq/elvish/eval/builtin-func.go:72 +0x11d
github.com/xiaq/elvish/eval.println(0xc20803b320, 0xc20804f360, 0x2, 0x2, 0x0, 0x0)
/home/philip/projects/go/src/github.com/xiaq/elvish/eval/builtin-func.go:79 +0x175
github.com/xiaq/elvish/eval.func·010()
/home/philip/projects/go/src/github.com/xiaq/elvish/eval/exec.go:204 +0x5e
created by github.com/xiaq/elvish/eval.(*Evaluator).execBuiltinFunc
/home/philip/projects/go/src/github.com/xiaq/elvish/eval/exec.go:209 +0xcf
goroutine 16 [chan receive]:
github.com/xiaq/elvish/eval.func·014(0xc20803a120, 0x0, 0x0, 0x0)
/home/philip/projects/go/src/github.com/xiaq/elvish/eval/op.go:102 +0x5a2
github.com/xiaq/elvish/eval.func·012(0xc20803a120)
/home/philip/projects/go/src/github.com/xiaq/elvish/eval/op.go:31 +0xb0
github.com/xiaq/elvish/eval.(*Evaluator).eval(0xc20803a120, 0xc208000318, 0x7, 0xc20804e8c0, 0x1f, 0xc2080cd9a0, 0x0, 0x0)
/home/philip/projects/go/src/github.com/xiaq/elvish/eval/eval.go:145 +0xdd
github.com/xiaq/elvish/eval.(*Evaluator).Eval(0xc20803a120, 0xc208000318, 0x7, 0xc20804e8c0, 0x1f, 0xc20804e9c0, 0x0, 0x0)
/home/philip/projects/go/src/github.com/xiaq/elvish/eval/eval.go:134 +0x10f
main.interact()
/home/philip/projects/go/src/github.com/xiaq/elvish/main.go:70 +0x65e
main.main()
/home/philip/projects/go/src/github.com/xiaq/elvish/main.go:118 +0x2c
goroutine 19 [finalizer wait]:
runtime.park(0x414c00, 0x81b538, 0x8101e9)
/home/philip/projects/f/go/src/pkg/runtime/proc.c:1369 +0x89
runtime.parkunlock(0x81b538, 0x8101e9)
/home/philip/projects/f/go/src/pkg/runtime/proc.c:1385 +0x3b
runfinq()
/home/philip/projects/f/go/src/pkg/runtime/mgc0.c:2644 +0xcf
runtime.goexit()
/home/philip/projects/f/go/src/pkg/runtime/proc.c:1445
goroutine 20 [syscall]:
os/signal.loop()
/home/philip/projects/f/go/src/pkg/os/signal/signal_unix.go:21 +0x1e
created by os/signal.init·1
/home/philip/projects/f/go/src/pkg/os/signal/signal_unix.go:27 +0x32
goroutine 17 [syscall]:
runtime.goexit()
/home/philip/projects/f/go/src/pkg/runtime/proc.c:1445
goroutine 21 [syscall]:
syscall.Syscall(0x0, 0x3, 0x7fe5d6bf7ea1, 0x1, 0x1, 0x1, 0x417eb5)
/home/philip/projects/f/go/src/pkg/syscall/asm_linux_amd64.s:21 +0x5
syscall.read(0x3, 0x7fe5d6bf7ea1, 0x1, 0x1, 0x100000002, 0x0, 0x0)
/home/philip/projects/f/go/src/pkg/syscall/zsyscall_linux_amd64.go:838 +0x75
syscall.Read(0x3, 0x7fe5d6bf7ea1, 0x1, 0x1, 0xc208002120, 0x0, 0x0)
/home/philip/projects/f/go/src/pkg/syscall/syscall_unix.go:136 +0x5c
os.(*File).read(0xc208038030, 0x7fe5d6bf7ea1, 0x1, 0x1, 0x4ef560, 0x0, 0x0)
/home/philip/projects/f/go/src/pkg/os/file_unix.go:190 +0x62
os.(*File).Read(0xc208038030, 0x7fe5d6bf7ea1, 0x1, 0x1, 0x1, 0x0, 0x0)
/home/philip/projects/f/go/src/pkg/os/file.go:95 +0x98
github.com/xiaq/elvish/util.(*AsyncReader).run(0xc208022720)
/home/philip/projects/go/src/github.com/xiaq/elvish/util/async-reader.go:89 +0x4b7
created by github.com/xiaq/elvish/util.NewAsyncReader
/home/philip/projects/go/src/github.com/xiaq/elvish/util/async-reader.go:44 +0x15e
goroutine 22 [chan receive]:
github.com/xiaq/elvish/edit.(*Reader).stop(0xc2080227b0, 0xc208004240)
/home/philip/projects/go/src/github.com/xiaq/elvish/edit/reader.go:245 +0x51
github.com/xiaq/elvish/edit.(*Reader).run(0xc2080227b0)
/home/philip/projects/go/src/github.com/xiaq/elvish/edit/reader.go:271 +0x1ea
created by github.com/xiaq/elvish/edit.NewReader
/home/philip/projects/go/src/github.com/xiaq/elvish/edit/reader.go:75 +0xe6
philip@indiana:~$ go version
go version go1.3 linux/amd64
Probably should not be doing that.
Have you considered something like the Redis protocol?
http://redis.io/topics/protocol
It's easy to understand and extensible, streamable, and could support complex objects.
It would be nice to follow clojure's approach and have immutable data structures by default.
Pros:
Facilitates concurrency
Avoids the reference vs. value semantics problem; consider the following in Python:
>>> a = [[1]] * 5
>>> a
[[1], [1], [1], [1], [1]]
>>> a[0][0] = 2
>>> a
[[2], [2], [2], [2], [2]]
However, we'd better still have $env
and namespaces as mutable maps.
Hi,
On two new machines running debian jessie, I get
go get github.com/xiaq/elvish
github.com/elves/elvish/eval
go/bin/src/github.com/elves/elvish/eval/builtin_special.go:281: undefined: os.Unsetenv
Thanks
Raphael
I can't normaly use shell without history!
There is a const named ItemAmbiguious.
edit.Highlighter
is now backed by parse.Lexer
. It processes a flow of tokens, identify commands and variables, resolve their validness and highlight them accordingly. However,
Highlighter
does a poor job on this. This requires the use of Parser
.x
in fn x { }; x
is actually valid is impossible without knowing about the fn
form. This requires the use of Compiler
.The plan: Highlighter
should be backed by parser.Parser
and eval.Compiler
. It parses the (incomplete) text and in case of syntax errors, highlight the affected areas. It then compiles the tree and highlights any static type errors. The plan consists of several parts:
Parser
needs to handle incomplete text better; it also needs to be able to continue parsing to some extent in face of errors (or a single syntax error will cause everything after it to not be parsed).Compiler
also needs to continue compiling to some extent in face of errors.Compiler
simply mark all unresolved commands as externals, and does not attempt to resolve them into actual paths. Compiler
needs to make it possible to enumerate such commands after compiling an AST.Highlighter
. The structure of Highlighter
may also need a change. Since parsing and compiling can be a bit time-consuming, running the text through Highlighter
before displaying them on screen can cause lags. Highlighter
may now output a series of highlighting instructions. Editor
displays the text immediately (with proper ItemType
highlighting), run Highlighter
asynchronously and apply the instructions once they are ready.A few things about the shell need to be stored persistently:
Traditionally, command history is stored in a file, but this has caused a number of complexities (cf. zsh's history-related options).
It would be better if a devoted agent manages persistent storage and mediates its access, like how fishd manages universal variables for fish.
Currently you cannot invoke pipelines with channel output interactively, since stdout is a fd port. As a result, arithmetic examples in README are broken and require a trailing | printchan
to work:
~> / 1 0
<tty 2>:1:1: error: pipeline output not satisfiable
/ 1 0
^
~> / 1 0 | printchan
+Inf
It would be nice if the printchan
above is implicit. However, the printchan
is better left explicit in scripts. There are two options of doing this:
printchan
command to such pipelines, but only in interactive mode. However this makes code that are correct in interactive mode incorrect in scripts.| printchan
before compiling and executing. This requires a bit more work.Option 2 is better.
The following behavior is not desired:
~> fn f { echo "Hello, ""world!" }
~> f
Hello, world!
~> f
Hello, world!world!
Persistent variables and persistent functions are shared across multiple sessions and preserved on shell exits. They are useful for passing data or code between concurrent sessions without (explicit) serialization/deserialization. In particular, they are ideal for configuration variables and functions and may serve as a more advanced clipboard facility.
The ideas are taken from fish, which has universal variable and autoload functions, with quite different implementations. All universal variables are stored into one file, and fish
instances talk to an agent, fishd
, to access them. In the case of autoload functions, however, each function is stored into a separate file and there is no agent to coordinate the access. Users are encouraged to manage autoload functions manually.
Open questions:
elvished
package already includes a prototype of the agent.)Hi,
Thanks for your new shell. It looks very promising. I would like to know if you have considered bundling somthing similar to autojump with your elvish?
In case you're not familiar with it, autojump (https://github.com/joelthelion/autojump) is a tool that learns the directories where you spend the most time and allows you to jump quickly to these directories. A lot of people have found it useful. Autojump is not built into the shells it extends, and as a result it is a bit fragile and difficult to maintain. Having it built into elvish could be a great addition to the already very nice features of the new shell.
Feel free to close this issue if you think this is a bad idea, or simply not a priority.
I'd like to use UP and DOWN to both visit my command history and navigate directories.
Elvish should support simple job control. One particular use case is to suspend a foreground process with ^Z
, and use kill
to send it a process or use fg
to put it into foreground again.
On the other hand, control of background processes should be rethought and simplified. Today we have screen
and tmux
, and people now rarely do multiple things in the same shell session.
Clojure actually does have a way to avoid the reverse-order problem with Lisps that you lament in the README. Here is another way of writing your example Clojure code from the end of the README:
(require ['clojure.string :refer '(upper-case)])
(def strs '("aha" "LOLaha" "hahaLOL" "hum?"))
(def lols (->> strs
(filter #(re-find #"LOL" %))
(map upper-case)
sort))
As you can see, the functions are written in the order they are applied, by using the ->>
macro (similar to the ->
"thread" macro). I don't know enough about Clojure to say whether use of that macro is idiomatic or not, but Clojure does support it. You should note it as an alternative in your README.
Since fixing the problems with Lisps' pipelining seems to be one of the goals of your shell, you should consider Clojure's approach as an option.
There is an bash kernel for the IPython notebook (post by Jeroen Janssens). There should also be an elvish kernel!
linux/amd64/ubuntu12.04
version:
"commit 0c77f30
Author: Cheer Xiao [email protected]
Date: Tue Dec 9 14:40:04 2014 +0100
Pipes are no longer statically typed.
"
jaten@c03:$ go get -u -t -v github.com/elves/elvish
github.com/elves/elvish (download)
jaten@c03:~$ elvish
panic: runtime error: invalid memory address or nil pointer dereference
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x4592ec]
goroutine 16 [running]:
runtime.panic(0x5302e0, 0x80d6b3)
/home/jaten/pkg/go1.3.1/go/src/pkg/runtime/panic.c:279 +0xf5
github.com/elves/elvish/edit.(*writer).commitBuffer(0xc208000320, 0x0, 0x0, 0x0)
/home/jaten/go/src/github.com/elves/elvish/edit/writer.go:216 +0x6c
github.com/elves/elvish/edit.(*writer).refresh(0xc208000320, 0xc20808a040, 0x0, 0x0, 0x0, 0x0, 0x0)
/home/jaten/go/src/github.com/elves/elvish/edit/writer.go:538 +0x1cd4
github.com/elves/elvish/edit.(*Editor).refresh(0xc20808a000, 0x0, 0x0)
/home/jaten/go/src/github.com/elves/elvish/edit/editor.go:121 +0x21b
github.com/elves/elvish/edit.(*Editor).finishReadLine(0xc20808a000, 0xc2080247e0)
...
Current flow of source code:
source code [parser]-> AST [checker]-> annotated AST [evaluator]-> effects
That is, the checker checks and annotates the AST with information available statically and the evaluator evaluates the annotated AST. This poses two problems:
eval
package, AST nodes in parse
. eval
imports parse
; since golang forbids cyclic imports, parse
cannot import eval
and AST nodes cannot contain annotation types directly. To work around this, all annotations are typed interface{}
and the Checker and Evaluator make type assertions everywhere.The plan is to introduce a new component, a compiler that takes up the role of the checker and much of the evaluator. Instead of checking and annotating the AST, the compiler performs deferred evaluation of the AST. For instance, a factor is evaluated into a func(*Evaluator) []Value
, where currently, the evaluator evaluates it into a []Value
. Similar things apply to all levels of the AST, from terms to chunks.
This would solve the aforementioned problems, but by using closures extensively it could also make debugging a bit harder.
philip@indiana:~$ go version
go version go1.3 linux/amd64
philip@indiana:~$ elvish
~> + 1 2
<tty 1>:1:1: error: pipeline output not satisfiable
+ 1 2
^
Traditionally Unix shells have no booleans. Instead of taking a boolean, if
takes a command (actually a pipeline) and executes the body depending on whether the command has succeeded or not.
Perhaps we could introduce booleans and see how it fares better.
Related to #13.
It is not yet possible to execute a file. It should be.
I've just written a small PKGBUILD
file to install elvish on Archlinux through the user repository:(AUR)
https://aur.archlinux.org/packages/elvish-git/
I thought you'd like to be notified =)
In Elvish, blocks in control structures like if
, for
, etc. are really just closures. This simplifies scoping and encourages use of higher order function.
However, using closures as blocks require one important extension: flow control commands like return
, continue
and break
need to have knowledge of the surrounding closure. For instance, in
fn f {
if true {
return 1
}
}
The return
terminates the fn
-block, not the if
-block.
Open questions:
for
can be implemented by the user?The keybinding is now fixed, but should really be customizable. New builtins needs to be introduced to modify the keybinding.
While tables are first class values in elvish, it is not yet possible to manipulate them. To break it down, it should be possible to add, remove and modify elements of a table.
We can either go the conventional way of mutable data structures or adopt immutable data structures (#11.)
It should be possible to access the command line history from elvish code.
The session history is simple and can be exposed as a $history
array. The persistent history involves database reads and the API should be designed more carefully.
The traditional approach is:
$?
and ignored by default (unless -e
is set).$PIPESTATUS
, in zsh $pipestatus
. However, only the return value of the last command goes into $?
and interacts with -e
.if
takes a pipeline and if the pipeline has non-zero exit value ($?
, not $PIPESTATUS
), the enclosed block is executed.Maybe we can do better, but I'm not sure which way to go. Some choices:
$?
/$PIPESTATUS
mess a bit;The decision can affect how if
should work.
I wish we could:
Make a clear distinction of Error vs. Exception. Of the aforementioned choices, only golang does this;
Make it easy to reason about intermediate states should an exception/error occur. As an example of intermediate state, in
var $a $b = (echo a | tee /tmp/a | feedchan)
The assignment fails, but /tmp/a
is created.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.