udayvir-singh / tangerine.nvim Goto Github PK
View Code? Open in Web Editor NEW๐ Sweet Fennel integration for Neovim
License: MIT License
๐ Sweet Fennel integration for Neovim
License: MIT License
My PR #24 got closed, so I fork on my machine, and fixed Windows issue, but I didn't pull upstream after July, 2023.
Here's the diff:
diff --git a/fnl/tangerine/api/compile.fnl b/fnl/tangerine/api/compile.fnl
index 209aada..e3e858f 100644
--- a/fnl/tangerine/api/compile.fnl
+++ b/fnl/tangerine/api/compile.fnl
@@ -133,8 +133,8 @@
"compiles the current active vim buffer."
;; opts { :float boolean :verbose boolean :filename string :globals list }
(local opts (or ?opts {}))
- (let [bufname (vim.fn.expand :%:p)
- sname (vim.fn.expand :%:t)
+ (let [bufname (env.expand :%:p)
+ sname (env.expand :%:t)
target (p.target bufname)]
:compile
(hpcall! #(compile.file bufname target (tbl-merge opts {:filename sname}))
diff --git a/fnl/tangerine/api/eval.fnl b/fnl/tangerine/api/eval.fnl
index 9b376af..db0faeb 100644
--- a/fnl/tangerine/api/eval.fnl
+++ b/fnl/tangerine/api/eval.fnl
@@ -11,6 +11,7 @@
(local {
: p
: fs
+ : env
} (require :tangerine.utils))
(local {
@@ -30,7 +31,7 @@
(lambda get-bufname []
"returns name of current buffer, parses [No Name] correctly."
- (let [bufname (vim.fn.expand :%:t)]
+ (let [bufname (env.expand :%:t)]
(if (not= bufname "") bufname
:else "[No Name]")))
diff --git a/fnl/tangerine/fennel.fnl b/fnl/tangerine/fennel.fnl
index e34fbdf..02cda5c 100644
--- a/fnl/tangerine/fennel.fnl
+++ b/fnl/tangerine/fennel.fnl
@@ -32,7 +32,7 @@
(table.insert out (format-path t ext macro-path?)))
; rtp dirs
(each [entry (rtps:gmatch "(.-),")]
- (local glob (vim.fn.glob (.. entry "/fnl/") 0 1))
+ (local glob (env.glob-list (.. entry "/fnl/") 0 1))
(each [_ path (ipairs glob)]
(table.insert out (format-path path ext macro-path?))))
:return
diff --git a/fnl/tangerine/utils/env.fnl b/fnl/tangerine/utils/env.fnl
index ff37cf1..2bb037c 100644
--- a/fnl/tangerine/utils/env.fnl
+++ b/fnl/tangerine/utils/env.fnl
@@ -6,7 +6,22 @@
;; -------------------- ;;
;; Utils ;;
;; -------------------- ;;
-(local config-dir (vim.fn.stdpath :config))
+(local windows? (= (vim.fn.has "win32") 1))
+
+(lambda cvt-backslash [path]
+ (if windows? (pick-values 1 (string.gsub path "\\" "/")) path))
+
+(local config-dir (cvt-backslash (vim.fn.stdpath :config)))
+
+(lambda expand [...]
+ (cvt-backslash (vim.fn.expand ...)))
+
+(lambda glob-list [...]
+ (icollect [_ v (ipairs (vim.fn.glob ...))]
+ (-?> v (cvt-backslash))))
+
+(lambda resolve-and-expand [...]
+ (cvt-backslash (vim.fn.resolve (vim.fn.expand ...))))
(lambda endswith [str args]
"checks if 'str' ends with one of arr::'args'."
@@ -16,7 +31,7 @@
(lambda resolve [path]
"resolves 'path' to POSIX complaint absolute path."
- (let [out (vim.fn.resolve (vim.fn.expand path))]
+ (let [out (resolve-and-expand path)]
(if (endswith out ["/" ".fnl" ".lua"])
(do out)
(.. out "/"))))
@@ -50,7 +65,8 @@
(lambda luafmt []
"returns default lua formatter for ENV."
- (let [exec (vim.fn.expand "~/.luarocks/bin/lua-format")
+ (let [exec (if (= vim.fn.executable "lua-format" 1)
+ "lua-format" (vim.fn.expand "~/.luarocks/bin/lua-format"))
width (vim.api.nvim_win_get_width 0)]
:return [
exec
@@ -273,4 +289,7 @@
:get env-get
:set env-set
:conf env-get-conf
+ : expand
+ : resolve-and-expand
+ : glob-list
}
diff --git a/fnl/tangerine/utils/path.fnl b/fnl/tangerine/utils/path.fnl
index a2fe0ed..67bb0f4 100644
--- a/fnl/tangerine/utils/path.fnl
+++ b/fnl/tangerine/utils/path.fnl
@@ -17,7 +17,7 @@
(lambda p.resolve [path]
"resolves 'path' to POSIX complaint path."
- (vim.fn.resolve (vim.fn.expand path)))
+ (vim.fn.resolve (env.expand path)))
;; ------------------------- ;;
@@ -31,9 +31,9 @@
(lambda p.transform-path [path [key1 ext1] [key2 ext2]]
"changes path's parent dir and extension."
- (let [from (.. "^" (esc-regex (env.get key1)))
- to (esc-regex (env.get key2))
- path (path:gsub (.. "%." ext1 "$") (.. "." ext2))]
+ (let [from (.. "^" (esc-regex (p.resolve (env.get key1))))
+ to (esc-regex (p.resolve (env.get key2)))
+ path (: (p.resolve path) :gsub (.. "%." ext1 "$") (.. "." ext2))]
(if (path:find from)
(path:gsub from to)
(path:gsub (.. "/" ext1 "/") (.. "/" ext2 "/")))))
@@ -58,7 +58,7 @@
;; -------------------- ;;
(lambda p.goto-output []
"open lua:target of current fennel buffer."
- (let [source (vim.fn.expand :%:p)
+ (let [source (env.expand :%:p)
target (p.target source)]
(if (and (= 1 (vim.fn.filereadable target))
(not= source target))
@@ -72,7 +72,7 @@
;; -------------------- ;;
(lambda p.wildcard [dir pat]
"expands wildcard 'pat' inside of 'dir' and return array of paths."
- (vim.fn.glob (.. dir pat) 0 1))
+ (env.glob-list (.. dir pat) 0 1))
:return p
I was patching fs.fnl like PR #29, but we should support compile hooks, to compile fnl to lua "onsave", so you need modify deep down to compile.fnl and eval.fnl, so I put those patched functions to env.fnl.
@Sharparam, hope these codes helps you to make a new PR, my coding skill really sucks and I don't think my patch should get merge to upstream, I'm not a professional programmer anyway.
Just by importing macros via (import-macros {: set!} :macros.opt-macros)
, I get the compile error below. Not sure the compiler should even evaluate the macro expressions given I haven't called a macro function just yet.
:: COMPILE ERROR
xxx core/options.fnl
Compile error in core/options.fnl:1:0
Compile error in /home/oblitz/.config/nvim/fnl/macros/opt-macros.fnl:30:16
Compile error in /home/oblitz/.config/nvim/fnl/macros/opt-macros.fnl:30:28
expected quoted expression for expr
(quoted->fn value)
stack traceback:
[C]: in function 'error'
.../nvim/lazy/tangerine.nvim/lua/tangerine/fennel/1-2-1.lua:3510: in function 'assert-compile'
.../nvim/lazy/tangerine.nvim/lua/tangerine/fennel/1-2-1.lua:2242: in function '__fnl_global__assert_2dcompile'
/home/oblitz/.config/nvim/fnl/macros/lib/compile-macros.fnl:20: in function </home/oblitz/.config/nvim/fnl/macros/lib/compile-macros.fnl:18>
[C]: in function 'xpcall'
.../nvim/lazy/tangerine.nvim/lua/tangerine/fennel/1-2-1.lua:2754: in function 'macroexpand_2a'
.../nvim/lazy/tangerine.nvim/lua/tangerine/fennel/1-2-1.lua:2941: in function 'compile1'
.../nvim/lazy/tangerine.nvim/lua/tangerine/fennel/1-2-1.lua:1247: in function 'compile_body'
.../nvim/lazy/tangerine.nvim/lua/tangerine/fennel/1-2-1.lua:1258: in function 'special'
.../nvim/lazy/tangerine.nvim/lua/tangerine/fennel/1-2-1.lua:2779: in function 'compile1'
.../nvim/lazy/tangerine.nvim/lua/tangerine/fennel/1-2-1.lua:3014: in function 'compile_top_target'
...
.../nvim/lazy/tangerine.nvim/lua/tangerine/fennel/1-2-1.lua:2051: in function 'require-macros'
src/fennel/macros.fnl:343: in function <src/fennel/macros.fnl:328>
[C]: in function 'xpcall'
.../nvim/lazy/tangerine.nvim/lua/tangerine/fennel/1-2-1.lua:2754: in function 'macroexpand_2a'
.../nvim/lazy/tangerine.nvim/lua/tangerine/fennel/1-2-1.lua:2941: in function 'compile1'
.../nvim/lazy/tangerine.nvim/lua/tangerine/fennel/1-2-1.lua:3208: in function 'string'
...e/nvim/lazy/tangerine.nvim/lua/tangerine/api/compile.lua:58: in function <...e/nvim/lazy/tangerine.nvim/lua/tangerine/api/compile.lua:48>
[C]: in function 'xpcall'
...e/nvim/lazy/tangerine.nvim/lua/tangerine/api/compile.lua:212: in function 'run'
[string ":lua"]:1: in main chunk
Please add support for newer versions of Fennel, such as 1.3.1 and 1.4.0
I was trying g
commands on neovim, and I realized that when I'm on a non-fennel file, the tangerine mappings are still enabled, which is terrible.
Could we set shortcuts only in fennel files?
I'm not sure if the error is on my side or Tangerine, but as I'm stuck for like an hour now, I'm hoping for help..
I'm trying to modify the plugins/0-tangerine.lua
to bootstrap not only Fennel, but Packer as well and install all the packages. All I have converted to Fennel is currently the init.lua
. Full config here, local changes are moving lua/
to fnl/
, adding Tangerine/Hibiscus to fnl/d12bb/plugins.lua
and converting init.lua
to init.fnl
. When not bootstrapping (Packer and plugins already installed), the config works just fine.
local function bootstrap(url)
local name = url:gsub(".*/", "")
local path = vim.fn.stdpath([[data]]) .. "/site/pack/packer/start/" .. name
if vim.fn.isdirectory(path) == 0 then
print(name .. ": installing in data dir...")
vim.fn.system({ "git", "clone", "--depth", "1", url, path })
vim.cmd([[redraw]])
print(name .. ": finished installing")
return true -- return true to know it wasn't installed before
end
end
local tangerine_bootstrap = bootstrap("https://github.com/udayvir-singh/tangerine.nvim")
bootstrap("https://github.com/udayvir-singh/hibiscus.nvim")
require("tangerine").setup({
rtpdirs = { "compiler", "ftplugin" },
compiler = {
hooks = { "onsave", "oninit" },
},
eval = {
luafmt = function()
return "/opt/homebrew/bin/stylua"
end,
},
})
if tangerine_bootstrap then
_G.tangerine.api.compile.all() -- doesn't work, no `lua/tangerine_vimrc.lua` created
-- also tried require("tangerine").api.. and just tangerine.api..
end
if bootstrap("https://github.com/wbthomason/packer.nvim") then
-- when using `lua/tangerine_vimrc.lua` already compiled, this fails with the error below
require("d12bb.plugins") -- contains only require("packer").startup(...)
require("packer").sync()
end
packer.nvim: finished installing
Error detected while processing /Users/bene/.config/nvim/plugin/0-tangerine.lua:
E5113: Error while calling lua chunk: /Users/bene/.config/nvim/plugin/0-tangerine.lua:32: loop or previous e
rror loading module 'd12bb.plugins'
stack traceback:
[C]: in function 'require'
/Users/bene/.config/nvim/plugin/0-tangerine.lua:32: in main chunk
(require-macros :hibiscus.core)
(require-macros :hibiscus.vim)
(g! mapleader " ")
(set! shell "fish")
(set! colorcolumn "+1")
(set! completeopt "menu,menuone,noinsert")
(set! cursorline true)
(set! expandtab false
(set! formatoptions "jcroql")
(set! grepformat "%f:%l:%c:%m")
(set! grepprg "rg --vimgrep"))
(set! guifont "FiraCode Nerd Font Mono")
(set! hlsearch false) ;; autotoggled when searching, see user.autocmds
(set! ignorecase true)
(set! laststatus 3)
(set! linebreak false)
(set! list true)
(set! listchars "tab:> ,lead:ยท,trail:ยท,extends:โข,precedes:โ ,nbsp:+")
(set! mouse "a")
(set! number true)
(set! relativenumber true)
(set! scrolloff 3)
(set! shelltemp false) ;; use pipe instead of tmp file for shell commands
(set! shiftwidth 4)
(set! signcolumn "yes")
(set! smartcase true)
(set! splitbelow true)
(set! splitright true)
(set! tabstop 4)
(set! termguicolors true)
(set! textwidth 100)
(set! timeoutlen 500)
(set! undofile true)
(set! wildmode "longest:full,full")
(vim.diagnostic.config { :virtual_text false })
;; :h ft_rust.txt
(g! rust_fold 1)
(g! rust_recommended_style 0) ;; would set expandtab otherwise
(require :d12bb.plugins)
(require :d12bb.misc)
(require :d12bb.cmp)
(require :d12bb.lsp)
(let [keymaps (require :d12bb.keymaps)] (keymaps.general)) ;; TODO: is there a more elegant way?
(require :d12bb.autocmds)
(g! gruvbox_baby_background_color "dark")
(g! gruvbox_baby_telescope_theme 1)
(color! gruvbox-baby)
(let [lualine (require :lualine)] (lualine.setup))
(when (and (boolean? vim.g.neovide) (= vim.g.neovide true))
(g! neovide_remember_window_size true)
(if (= vim.fn.getcwd "/")
(vim.api.nvim_set_current_dir "~")))
When setting up the globals
option for compiling a dir, I have to first create the vim.tbl_keys(_G)
table before I can add in new global values like awesome
(for AwesomeWM). Otherwise, if I just add the new global values, it will cause a compilation error where it doesn't recognize functions like pcall
and require
. Unless I'm doing something incorrectly.
My suggestion is that the custom values should add on to the default values instead of replace it.
Maybe add a clear_default_globals
option if you truly wanted to replace the default values.
Maybe even rename globals
to custom_globals
to be more precise,
When i run :FnlCompile
with code below:
(paq {
"savq/paq-nvim"
"udayvir-singh/tangerine.nvim"
"kyazdani42/nvim-tree.lua"
"nvim-treesitter/nvim-treesitter"
"windwp/nvim-autopairs"
})
I got this error:
:: COMPILE ERROR
xxx nvim/init.fnl
Parse error in nvim/init.fnl:9
expected even number of values in table literal
* Try removing a key.
* Try adding a value.
It compiled well when i use brackets instead of braces like this:
(paq [
"savq/paq-nvim"
"udayvir-singh/tangerine.nvim"
"kyazdani42/nvim-tree.lua"
"nvim-treesitter/nvim-treesitter"
"windwp/nvim-autopairs"
])
Basically what's wrong: it seems that Git cannot properly load symlinks.
So tangerine.fennel.latest becomes an invalid lua file with symlinked path as content.
I noticed that FnlPeak
targets a range but it'd be nice to target a specific node also. I feel like that's the more sensible way to do Fennel peaks.
Got the idea from Olical/conjure where you can evaluate a specific node (e.g. word node, current node, root node, etc.).
for example, macros modules probably shouldn't be compiled.
I was reading documentation and one part caught my attention.
-- hooks for tangerine to compile on:
-- "onsave" run every time you save fennel file in {source} dir.
-- "onload" run on VimEnter event
-- "oninit" run before sourcing init.fnl [recommended than onload]
I was trying to compile "rtpdirs" on "onsave hook", but I have not found a way, how can I get this result?
Whenever a macro file is changed, Tangerine doesn't recompile the entire config, leaving some files that used those (now changed) macros to become outdated.
Check if any macro file has changed and recompile the entire config.
In issue #10 there was an issue with symbolic links in Git on windows, but this now works since some time back.
However, there's a different issue that now appears in tangerine:
Tangerine hardcodes /
(forward slash) as the path separator, including in places where it uses match
and friends to extract different parts of paths. This of course breaks on Windows which uses a \
(backslash).
It feels like it should be a simple enough fix, since Windows does support using /
as a separator it would probably be possible to just add support for converting automatically and also detecting \
in addition to /
in places such as the shortname
function and fs.write
.
The current OS is available in jit.os
so this special code could also be guarded so it does not run at all unless the user is on Windows, to prevent any possible issues that could occur by trying to support \
on Linux where it's not necessary.
I could look into making this work if a PR is welcome @udayvir-singh?
There are no docs here I could find. Bootstrapping standalone doesn't work, including Tangerine as a plugin in Lazy works, but it restricts using Lazy to Lua. It would be much appreciated if you added installation instructions for Lazy package manager.
I'm switching from hotpot
to tangerine`, and I've encountered this problem.
Error detected while processing /home/pop-os/.config/nvim/init.lua:
E5113: Error while calling lua chunk: /home/pop-os/.config/nvim/init.lua:39: module 'conf' not found:
no field package.preload['conf']
no file './conf.lua'
no file '/usr/share/luajit-2.1.0-beta3/conf.lua'
no file '/usr/local/share/lua/5.1/conf.lua'
no file '/usr/local/share/lua/5.1/conf/init.lua'
no file '/usr/share/lua/5.1/conf.lua'
no file '/usr/share/lua/5.1/conf/init.lua'
no file './conf.lua'
no file './conf/init.lua'
no file '/home/pop-os/.config/nvim/fnl/conf.lua'
no file '/home/pop-os/.config/nvim/fnl/conf/init.lua'
no file '/home/pop-os/.config/nvim/fnl/conf.lua'
no file '/home/pop-os/.config/nvim/fnl/conf/init.lua'
no file '/home/pop-os/.config/nvim/lua/conf.lua'
no file '/home/pop-os/.config/nvim/lua/conf/init.lua'
no file './conf.so'
no file '/usr/local/lib/lua/5.1/conf.so'
no file '/usr/lib/x86_64-linux-gnu/lua/5.1/conf.so'
no file '/usr/local/lib/lua/5.1/loadall.so'
stack traceback:
[C]: in function 'require'
/home/pop-os/.config/nvim/init.lua:39: in main chunk
nvim/
โโโ fnl
โย ย โโโ conf
โย ย โโโ bindings.fnl
โย ย โโโ init.fnl
โย ย โโโ macros.fnl
โย ย โโโ pack
โย ย โย ย โโโ cmp.fnl
โย ย โย ย โโโ dap.fnl
โย ย โย ย โโโ indent-blankline.fnl
โย ย โย ย โโโ lsp.fnl
โย ย โย ย โโโ neorg.fnl
โย ย โย ย โโโ null-ls.fnl
โย ย โย ย โโโ telescope.fnl
โย ย โย ย โโโ treesitter.fnl
โย ย โย ย โโโ trouble.fnl
โย ย โย ย โโโ ultest.fnl
โย ย โโโ pack.fnl
โย ย โโโ settings.fnl
โโโ init.lua
โโโ spell
โโโ en.utf-8.add
โโโ en.utf-8.add.spl
4 directories, 18 files
init.lua
function ensure(user, repo)
local install_path = string.format("%s/packer/start/%s", vim.fn.stdpath("data") .. "/site/pack", repo, repo)
if vim.fn.empty(vim.fn.glob(install_path)) > 0 then
vim.api.nvim_command(string.format("!git clone https://github.com/%s/%s %s", user, repo, install_path))
vim.api.nvim_command(string.format("packadd %s", repo))
end
end
-- Bootstrap essential plugins
ensure("wbthomason", "packer.nvim")
ensure("udayvir-singh", "tangerine.nvim")
ensure("lewis6991", "impatient.nvim")
-- impatient optimization
require("impatient")
require("tangerine").setup({
compiler = {
hooks = {
"oninit",
"onsave"
}
}
})
require("conf")
On default config is
vim.stdpath [[config]]
But the right thing is
vim.fn.stdpath [[config]]
Hello!
I am trying to make a proof of concept with tangerine but found a block when migrating my macros from hotpot to tangerine.
As you can see in the following screenshot the compilation fails when trying to compile my macro module.
The error is the following:
:: COMPILE ERROR
xxx conf/macro/pack.fnl
Compile error in conf/macro/pack.fnl:21
unknown identifier in strict mode: assert-compile
I have the code in a Github repository that you can see here. The repository can be executed using Docker for if you want to personally test it.
Hi there ๐
Firstly, thanks for creating this project! I've tried a few of the options out there and found the experience with tangerine to be superior in many ways!
I wanted to ask if there's currently a way to silence the output when running 'FnlFile ..'?
I find that i don't really need it and it gets in the way of my workflow of auto evaluating and running packer sync when my plugins file is changed.
I'm more than happy to contribute with this change if needed, but wanted to get your input first.
What I was thinking was adding a 'verbose' option to 'eval', similar to 'compile'. What do you think?
Thanks!
Compiled fennel to lua files go to target
Fennel compiles into source
-- init.lua
local function bootstrap(user, repo)
local fn = vim.fn
local install_path = fn.stdpath("data") .. "/lazy/" .. repo
if (fn.empty(fn.glob(install_path)) > 0) then
fn.system({"git", "clone", "--depth", "1", ("https://github.com/" .. user .. "/" .. repo.. ".git"), install_path})
end
vim.opt.runtimepath:prepend(install_path)
end
bootstrap("folke", "lazy.nvim")
bootstrap("udayvir-singh", "tangerine.nvim")
local config = vim.fn.stdpath [[config]]
require "tangerine".setup({
source = config .. "/fnl",
target = vim.fn.stdpath [[cache]] .. "/lua",
compiler = {
hooks = {"onsave", "oninit"},
},
})
require("init")
Though if there's init.fnl
it alone compiles into target
.
I'm not sure if it's difficult to implement, but It'd be nice to jump to the equivalent node at cursor position when running a command like FnlGoToOutput
.
This would be useful for running proxy commands to the Lua LSP server. For instance, you create a command that jumps to the equivalent node in the Lua output, then runs the "go to definition" lsp command in the Lua output.
Would be nice to have separated /fnl
and /lua
folders in rtpdirs also.
After migrating from Packer to lazy everything was working fine until an update of lazy.
In this update, they removed silent
from a command and then I started to get this error from tangerine:
[tangerine]: ERROR LOADING VIMRC...
loop or previous error loading module 'tangerine_vimrc'
After some hours of deep investigation, I found out the reason.
Lazy disables loadplugins
(loading files in plugin/
folder), so it can source them later, but this was causing a loop because of tangerine's flow.
What happens is:
init.lua
, plugin/0-tangerine.lua
is loadedrequire'tangerine'
lua/tangerine_vimrc.lua
require'lazy'
plugin/0-tangerine.lua
<- here is where the loop beginsI know that this isn't an issue with tangerine itself, but since I could solve this by moving the plugin/0-tangerine.lua
file to ./init.lua
, I think it would be nice to add something in README to warn people that use lazy to not create the file in plugin/
folder
Currently, in order to mark a file as a macro, you are required to suffix it with -macros.fnl
, which is not ideal.
Normal script files and macro files get mixed up, ending up in a hard-to-read project structure.
Separate normal files and macro files into fnl/
and macros/
folders respectively.
Doing so would make it easier to understand which files are to be treated as macros, and which need to be compiled into Lua.
Onsave compilation doesn't work when in awesome dir, but works when in nvim dir
Here's the awesome compile dir config:
local awesome_dir = os.getenv("HOME") .. "/.config/awesome"
_G.tangerine.api.compile.dir(
awesome_dir .. "/fnl",
awesome_dir .. "/lua",
{
globals = vim.list_extend(vim.tbl_keys(_G), {
"awesome",
"root",
"modkey",
"RC"
}),
hooks = { "onsave", "oninit" },
verbose = true,
}
)
Whenever I go to change my configs under ~/.config/nvim/fnl/
or even ~/.config/nvim/init.fnl
, it sometimes doesn't compile after changes. After re-opening the file it starts to work..? I am unsure of how this bug occurs or how to reproduce it.
I looked into the source code and checked with au BufWritePost
, the paths seem normal.
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.