phsym / prettytable-rs Goto Github PK
View Code? Open in Web Editor NEWA rust library to print aligned and formatted tables
Home Page: https://crates.io/crates/prettytable-rs
License: BSD 3-Clause "New" or "Revised" License
A rust library to print aligned and formatted tables
Home Page: https://crates.io/crates/prettytable-rs
License: BSD 3-Clause "New" or "Revised" License
The tic-tac-toe example prints one table after the other. Would it be possible to have a "tic-tac-toe-inplace" example, where the table is updated in place ? How would I go about that ?
I'm looking to use this to update a table in place that can grow (e.g. get more rows, so that columns get resized).
Online crate documentation should be automatically published to github-pages from travis-ci jobs.
Documentation must be organnised into subdirectories :
Due to this bug, I am unable to get colors in prettytable:
Stebalien/term#81
v0.5.1 fixes this
I got the following issue opened in another repository of mine phsym/sctp-sys#2.
It made me wondering if it would be a good idea to do it also for prettytable-rs
in order to match better with rustlang licensing.
Any thought about that, someone ?
Hi,
I'm currently developing a tool (Process-Query) with @keeperofdakeys . I would like to be able to use your library to print text such as:
total used free shared buff/cache available
Mem: 12202880 3768524 663128 459220 7771228 7804748
Note that the first column is left aligned, and the rest are right aligned.
So I was thinking of various ways to implement alignment helpers beyond just per cell.
I don't think that alignment as part of the table format is correct. It would either override everything, be copied as cells are added, or have to be a "default".
Each of these three has issues.
The override on everything, doesn't work in my case. You would need code that then allows Cell alignment to override table alignment. This adds complication.
Being copied as cells are added has it's own special issues. Consider (kinda pseudo code):
let mut table = Table::new();
table.add_row(vec![...]);
let format =FormatBuilder::new().alignment(LEFT);
table.set_format(format);
This means the format can change part way through the tables construction, which could lead to nasty surprises.
Finally, having a default, would mean that cells would need to be able to express "default" alignment. So another type in the alignment enum. But this means you need code to again, check for the default vs a real alignment, collect the default from the format. You also need to make sure the format doesn't set the default enum value itself. More edge cases.
I think the perhaps the easiest solution is a collection of map functions. map row and map column. This would allow the application of a function to each cell in the table. This could be alignment, or some other formatting, so would be rather generic.
Alternately, an iter for mut row could be added to allow "for c in row" and "for c in column": Again, similar to map.
What do you think? I'm happy to take your advice, and implement the solution.
PS: Later this may apply to padding in each cell also, as I have some specific padding / width requirements I'd like to meet.
TableSlice
typeSlice
trait and implement it for Table
and TableSlice
Range
, RangeTo
and RangeFrom
to get a slice with only subrange of rowsRangeFull
to get the slice with all the rows&Table
transmutable into &TableSlice
so a table can be treated as a sliceAsRef<TableSlice<'a>>
, Borrow<TableSlice>
, and/or Deref<TableSlice>
Table
Create a struct TableSlice<'a>
that wraps a ref to Table
, which offers capability to print only a specific range of rows.
Perhaps slice syntax may be used to obtain this wrapper.
eg :
let mut table = Table::new();
/* (...) */
let slice: TableSlice<'a> = table[1..3];
Edit : Using slice syntax is not possible yet, since Index returns only references
Next idea is to create a Slice<T>
trait with method slice(&self, T) -> TableSlice<'a>
and implement it for Table
and TableSlice
with T as Range
, RangeFull
, RangeFrom
, RangeTo
It will let us use the following syntax :
let mut table = Table::new();
/* (...) */
let slice: &'a TableSlice<'a> = table.as_ref();
let slice: TableSlice<'a> = table.slice(1..3);
let slice: TableSlice<'a> = table.slice(1..);
let slice: TableSlice<'a> = table.slice(..3);
let slice: TableSlice<'a> = table.slice(..);
It's quite borring to have to update appveyor script each time a new rust version is released.
Now that rustup s the official way of installing rust, it should be used in appveyor script.
I have rewritten the original issue
Hey there,
I would love to draw line separators with these symbols:
.separators( &[format::LinePosition::Top], format::LineSeparator::new('─', '┬', '┌', '┐'))
.separators( &[format::LinePosition::Intern], format::LineSeparator::new('─', '┼', '├', '┤'))
.separators( &[format::LinePosition::Bottom], format::LineSeparator::new('─', '┴', '└', '┘'))
however, there seems to be some sort of encoding problem, because they are not printed this way on the terminal
┌─────────────┬────────────┐
│ Title 1 | Title 2 │
├─────────────┼────────────┤
│ Value 1 | Value 2 │
├─────────────┼────────────┤
│ Value three | Value four │
└─────────────┴────────────┘
,
Title 1 Title 2
<$
Value 1 Value 2
<$
Value three Value four
4▒
Do you have an idea what goes wrong here?
Thanks
This is a proposal to remake Cell
and related functionality to simplify fixing issues #45, #46 and possibly #47 (since this proposal, if accepted, will allow defining custom behaviour of cell elements in case of the outer table being shrinked).
Here are some ways how this proposal can be implemented.
trait CellContent { ... }
impl CellContent for Vec<String> { ... } // represents lines
impl CellContent for Table { ... }
...
struct Cell<T: CellContent> {
content: T,
...
}
Cell
s, for other structs they're either avoidable, or have to do something with formatting and styling.cell!
macros can remain the same.String
. If this is the case this mode works perfectly fine)Table
's and Row
's backing storage is a homogeneous Vec
, the <T>
parameter would be needed to spread across the whole API.For trait definition see above
struct Cell {
content: Box<CellContent>, // could be other box structure here
...
}
Flexible: users will be able to define new types with their own behaviours in the table.
Easy to adapt existing public API:
Cell
constructors: types can be backwards-compatibly generalized, whereas the amount of constructors remains the same.cell!
macro wouldn't have to be modified at all.As a result, public API changes would be minimal and backwards-compatible.
Cell
has to store CellContent
boxed since we wouldn't know the exact type. This would certainly have performance implications, though their extent varies among usages.CellContent
implementations.enum CellContentBox {
Text(Vec<String>), // represents lines
Table(Table),
...
}
impl CellContentBox { ... }
struct Cell {
content: CellContentBox,
...
}
CellContentBox
and add implementation into all related functions and methods, which is a more cumbersome process than implementing a trait. It also makes code less clean and readable.Cell
constructors would probably have constructors for every enum variant.cell_*!
for every enum variant.UPD: More info about macros and wording.
AFAIU, you can set align only on a per-cell basis, but can I set an alignment for a whole column?
Many functions today are public and visible to crate's users. Their usage is internal to the crate and they should be private instead.
As an example, this has already been reported in #57.
Let's warn users by deprecating them in a first time, and give them time to bring feedback if they eventually use some of those functions
This will have the advantages of simplifying the API and its documentation, and removing those internal functions from public API will make it easier to introduce bigger changes without breaking the public API.
After making them private, they can still be brought back to public later if needed.
If you already use some of the deprecated functions, and want them to stay public, let me know in comments
Hi,
the docs say that TableFormat
gets a Option<char>
as first parameter, but passing None
results in:
src/ui/file.rs:165:45: 165:49 error: mismatched types:
expected `char`,
found `core::option::Option<_>`
Please fix. Besides, please continue contributing, I like your crate a lot!
The current nightly of rustc merged Type Ascription, which seems to collide with the format syntax of prettytable-rs.
Thank you for sharing this crate, it is a great one!!
Could you please #[derive(Hash)]
for the user facing data types? I want to put some tables in a HashMap
and need the Hash
trait.
It is always a good idea to implement the common traits listed in the API Guidelines. I think you have most of them except `Hash``.
EDIT: These are the traits I use for data types, following the API guidelines:
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
EDIT2: an impl of std::iter::Extend
for Row (to add cells) and Table (to add rows) will also be important to follow the API guidelines. I need this one even more than the HashMap
#[macro_use] extern crate prettytable;
extern crate ansi_term;
use prettytable::Table;
use ansi_term::Colour::Yellow;
fn main() {
// Okay
let mut table = Table::new();
table.add_row(row![ Fybl->"AAAAAAA", Fmbl->"BBB", Fgbl->"CCC"]);
table.add_row(row![ Fybl->"AAAAAAA", Fmbl->"BBB", Fgbl->"CCC"]);
table.add_row(row![ Fybl->"AAAAAAA", Fmbl->"BBB", Fgbl->"CCC"]);
table.add_row(row![ Fybl->"Yellow Yellow Yellow" ]);
table.printstd();
// Messed up
let mut table2 = Table::new();
table2.add_row(row![ Fybl->"AAAAAAA", Fmbl->"BBB", Fgbl->"CCC"]);
table2.add_row(row![ Fybl->"AAAAAAA", Fmbl->"BBB", Fgbl->"CCC"]);
table2.add_row(row![ Fybl->"AAAAAAA", Fmbl->"BBB", Fgbl->"CCC"]);
table2.add_row(row![ Yellow.bold().paint("Yellow Yellow Yellow") ]);
table2.printstd();
}
In table2
, the first column in the first 3 rows has extra paddings. Those paddings exist regardless of the alignment requested.
Hi, is there a way to have NO column separator (for very tight tables), without changing the API?
Thanks
Looks like having a trailing comma in row!()
invocation (and possibly other macros) results in infinite macro recursion.
I have something like this that triggers the error:
table.set_titles(row![
Fg -> "Foo",
Fg -> "Bar",
"Baz",
"Bad",
]);
Documentation on the link in the README.md is broken
Add capability to import from CSV, and export into CSV.
API should support strings, streams or files.
When the output of the table is piped into head
, the library panics. The issue was noticed in the measureme repo.
A minimal example would be
use prettytable::{Table, row, cell};
fn main() {
let mut table = Table::new();
for i in 1..=10 {
table.add_row(row!["ROW NUMBER", i]);
}
table.printstd();
}
Run this with cargo run | head
, and it will produce the output
$ RUST_BACKTRACE=1 cargo run | head
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target/debug/testtt`
+------------+----+
| ROW NUMBER | 1 |
+------------+----+
| ROW NUMBER | 2 |
+------------+----+
| ROW NUMBER | 3 |
+------------+----+
| ROW NUMBER | 4 |
+------------+----+
| ROW NUMBER | 5 |
thread 'main' panicked at 'Cannot print table to standard output : Broken pipe (os error 32)', /home/alice/.cargo/registry/src/github.com-1ecc6299db9ec823/prettytable-rs-0.8.0/src/lib.rs:194:23
stack backtrace:
0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
at src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:39
1: std::sys_common::backtrace::_print
at src/libstd/sys_common/backtrace.rs:70
2: std::panicking::default_hook::{{closure}}
at src/libstd/sys_common/backtrace.rs:58
at src/libstd/panicking.rs:200
3: std::panicking::default_hook
at src/libstd/panicking.rs:215
4: std::panicking::rust_panic_with_hook
at src/libstd/panicking.rs:478
5: std::panicking::continue_panic_fmt
at src/libstd/panicking.rs:385
6: std::panicking::begin_panic_fmt
at src/libstd/panicking.rs:340
7: prettytable::TableSlice::print_tty
at /home/alice/.cargo/registry/src/github.com-1ecc6299db9ec823/prettytable-rs-0.8.0/src/lib.rs:194
8: prettytable::TableSlice::printstd
at /home/alice/.cargo/registry/src/github.com-1ecc6299db9ec823/prettytable-rs-0.8.0/src/lib.rs:209
9: prettytable::Table::printstd
at /home/alice/.cargo/registry/src/github.com-1ecc6299db9ec823/prettytable-rs-0.8.0/src/lib.rs:376
10: testtt::main
at src/main.rs:8
11: std::rt::lang_start::{{closure}}
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/rt.rs:64
12: std::panicking::try::do_call
at src/libstd/rt.rs:49
at src/libstd/panicking.rs:297
13: __rust_maybe_catch_panic
at src/libpanic_unwind/lib.rs:87
14: std::rt::lang_start_internal
at src/libstd/panicking.rs:276
at src/libstd/panic.rs:388
at src/libstd/rt.rs:48
15: std::rt::lang_start
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/rt.rs:64
16: main
17: __libc_start_main
18: _start
Right now this library prints \r\n
on windows for newlines. This makes my tool a bit inconsistent, because the rest of the tool doesn't special-case for windows. In general I don't think it's a big issue for command-line tools to output unix newlines since windows isn't a natural command-line platform.
Can you add a way to turn off the platform specific newlines?
Hi @phsym,
I stumbled upon your crate for an application I'm writing and noticed that there isn't an easy way to create a table from columnar data. Have I missed this in the documentation, or is this yet to be implemented?
Thanks!
Mandeep
Every crate on crates.io is for Rust 😄 no reason for the -rs suffix.
I'm using this library for one of my programs, but I'm getting ANSI escape codes when piping the output (IE: The output isn't to a terminal). From a quick look at the code, there is a terminal detection feature. So I'm not sure why this is happening.
For reference, I'm on linux, using rxvt-unicode as my terminal And if it helps, here is where I'm calling your library - https://github.com/keeperofdakeys/Process-Query/blob/master/src/psq/main.rs#L21.
Inside Emacs's M-x shell
, the cargo benchcmp
command will always panic because of prettytable
:
$ cargo benchcmp ~/scratch/before ~/scratch/after
thread 'main' panicked at 'Cannot print table to standard output : operation not supported by the terminal', /Users/fitzgen/.cargo/registry/src/github.com-1ecc6299db9ec823/prettytable-rs-0.6.5/src/lib.rs:173
stack backtrace:
1: 0x103c9bafa - std::sys::backtrace::tracing::imp::write::h46f28e67d38b4637
2: 0x103c9dabf - std::panicking::default_hook::{{closure}}::h1d3243f546573ff4
3: 0x103c9cf85 - std::panicking::default_hook::h96c288d728df3ebf
4: 0x103c9d536 - std::panicking::rust_panic_with_hook::hb1322e5f2588b4db
5: 0x103c9d3d4 - std::panicking::begin_panic::hfbeda5aad583dc32
6: 0x103c9d2f2 - std::panicking::begin_panic_fmt::h4fe9fb9d5109c4bf
7: 0x103c05962 - prettytable::TableSlice::print_tty::h7f3d5c1f5cfe8a0a
8: 0x103bff5fd - cargo_benchcmp::Args::run::h5c6cc5028d1347fb
9: 0x103bfa6e9 - cargo_benchcmp::main::hb31fd77d8a66a286
10: 0x103c9e07a - __rust_maybe_catch_panic
11: 0x103c9cac6 - std::rt::lang_start::haaae1186de9de8cb
Ideally, prettytable
would check if pretty colors or whatever are supported (which M-x shell
actually will support, so maybe just removing whatever check will work?) and not use them if they aren't, rather than panicking.
(Originally filed as BurntSushi/cargo-benchcmp#15)
Table::printstd
panics when term crate cannot be used for some reason (eg : in gitlab-ci job console).
The function should fallback to stdout from stdlib if it cannot get an stdout from term crate
Code coverage is broken and always reports 0%
Many CLI programs use -H
for headerless and -p
for passable when it comes to printing tables. Reading the docs, I think that could be done by specifying a custom format, but it would be helpful to have a simple switch for those options.
It obscures important information on the left.
Once the table is styled and ready to print out, is it possible to iterate through the table and see what style each cell will be printed with?
When using Table
with ordinary characters I get a nice and pretty table like this:
+------+-------+-------+--------+-------+-------+--------+-------+--------+--------+
| | M1 | M2 | M4 | M5 | M10 | M15 | M20 | M30 | M60 |
+------+-------+-------+--------+-------+-------+--------+-------+--------+--------+
| VTBR | 7.55% | 0.21% | -4.37% | 1.56% | 8.49% | -1.78% | 4.95% | -5.95% | -3.80% |
+------+-------+-------+--------+-------+-------+--------+-------+--------+--------+
When I start to paint the text inside cells with ansi_term
crate, I get this:
+-------------+--------------+--------------+---------------+--------------+--------------+---------------+--------------+---------------+---------------+
| | M1 | M2 | M4 | M5 | M10 | M15 | M20 | M30 | M60 |
+-------------+--------------+--------------+---------------+--------------+--------------+---------------+--------------+---------------+---------------+
| VTBR | 7.55% | 0.21% | -4.37% | 1.56% | 8.49% | -1.78% | 4.95% | -5.95% | -3.80% |
+-------------+--------------+--------------+---------------+--------------+--------------+---------------+--------------+---------------+---------------+
Seems like ANSI chars are treated as 'normal' printable symbols which is obviously not true.
Unicode contains a set of characters to draw uninterrupted lines that can be used to create much cleaner, visually less noisy borders.
https://en.wikipedia.org/wiki/Box-drawing_character
Instead of
+---------+------+---------+
| ABC | DEFG | HIJKLMN |
+---------+------+---------+
| foobar | bar | foo |
+---------+------+---------+
| foobar2 | bar2 | foo2 |
+---------+------+---------+
you could create
┌─────────┬──────┬─────────┐
│ ABC │ DEFG │ HIJKLMN │
├─────────┼──────┼─────────┤
│ foobar │ bar │ foo │
├─────────┼──────┼─────────┤
│ foobar2 │ bar2 │ foo2 │
└─────────┴──────┴─────────┘
which is actually still interrupted vertically with the font my browser uses, but in my terminal and my editor those are connected.
Of course, legacy systems may not be able to deal with unicode, so you might want to keep it ASCII by default or at least add an ASCII fallback option.
I'm not currently a user of the library, I just chanced upon it when I was searching for crates to help me add this functionality to tokei. It seems to from the LineSeparator struct that the above table can't currently be created because there is only the distinction between junctions at the left and right border and the middle. Taking into account the top and bottom row, there are 5 junctions and 4 corners in total, not counting the half-bold, half-thin characters or half-single, half-double characters
Since Rust 1.30, macros can be individually imported with use
. This does not work for ptable!
, table!
and row!
, as they invoke other macros, which must be imported as well, exposing what can be considered implementation details. For example, the following code produces errors in both main
and test_ptable
:
fn main() {
use prettytable::row;
row!["x"];
}
fn test_ptable() {
use prettytable::ptable;
ptable!(["A", "B", "C"]);
}
error: cannot find macro `cell!` in this scope
[...]
error: cannot find macro `table!` in this scope
If we can bump the Rust requirement to 1.30, the fix is quite straightforward, namely prefixing macro invocations with $crate::
, see the edition guide. I'll submit a PR implementing this solution; unfortunatly, the solution (also explained in the edition guide) that works on older compilers as well is quite ugly IMO; I'll leave that as an exercise for the reader ;-).
I'm running a program on macOS. When using this section to put together a table:
for .. in .. {
let mut index_cell = Cell::from(&index);
index_cell.align(Alignment::RIGHT);
let mut item_cell = Cell::from(&item.name);
item_cell.style(Attr::ForegroundColor(0x00AAFF));
table.add_row(row![index_cell, item.name, amount]);
}
the program compiles and runs but I neither see the alignment option working nor the color. Did I do something wrong?
Table format customization API is a bit weird and not clean. Some refactoring should be done on it.
Builder Pattern may be use in a type named for example FormatBuilder
.
What should be customizable :
lazy_static
constantsFor example, this
let table = table!([["ABC", "DEFG", "HIJKLMN"],
["foobar", "bar", "foo"],
["foobar2", "bar2", "foo2"]]);
// there would be `_indented` counterparts for all printing methods if API shouldn't break
table.printstd();
table.printstd_indented(8);
renders
+---------+------+---------+
| ABC | DEFG | HIJKLMN |
+---------+------+---------+
| foobar | bar | foo |
+---------+------+---------+
| foobar2 | bar2 | foo2 |
+---------+------+---------+
+---------+------+---------+
| ABC | DEFG | HIJKLMN |
+---------+------+---------+
| foobar | bar | foo |
+---------+------+---------+
| foobar2 | bar2 | foo2 |
+---------+------+---------+
Would this be implemented sometime?
P.S. For convenience, a few table_print!
-like macros can be defined like
macro_rules! table_printstd {
($table:expr) => { $table.printstd() };
($table:expr, indent = $indent:expr) => { $table.printstd_indented($indent) };
}
/* define for other pairs of print methods */
I'm trying to generate a table like this
foo | bar | baz |
| | a | b |
===========+===========+=====+=====+
cat | 10 | 1 | 3 |
dog | 23 | 2 | 4 |
where one of the title cells has 2 rows, one row with a hspan of 2, and the other row has 2 cells, and the columns spanned by these two cells propagate to the rest of the table.
Is this possible ?
Dear sir,
I want to merge some cells, how to do it?
Do I just not see the difference here, or is this the same as the example above?
https://github.com/phsym/prettytable-rs/blob/master/examples/basic.rs#L45
Crates.io will start rejecting wildcard dependencies. They should be changed to more specific versions
#[macro_use] extern crate prettytable;
use prettytable::Table;
fn main() {
let in_table = table!([
Frbc->"Red",
Fgbc->"Green",
Fbbc->"Blue"
]);
let mut table = Table::new();
table.add_row(row![Frbc=> "Red", "Red", "Red", "Red"]);
table.add_row(row![in_table]);
in_table.printstd();
table.printstd();
}
When in_table
is added as a row in table
. It loses its styles.
On a related note. An option to automatically inherit the format of the outer table would be great.
Hi,
Is there any way to generate a table/csv that doesn't required all the values to be loaded in memory ?
It looks like iterators are supported in some cases but the iterator is converted into Vec of cells/rows before it gets written.
Sorry if this is not the right place to ask question
See #36
Each tab is rendered 8 spaces wide.
For example, with 17 levels of indentation the whole builder steps block is shifted out of the screen (its 1366 pixels wide in my case): http://phsym.github.io/prettytable-rs/v0.6.6/src/prettytable/src/format.rs.html#275-283.
Some solutions:
rustdoc
to render tabs 4 spaces wideP.S. Apparently, GitHub renders with 8 spaces too (https://github.com/phsym/prettytable-rs/blob/master/src/format.rs#L275-L283), so the first solution looks more viable to me now.
I would be neat if you could specify a max width for columns and/or tables and have prettytable automatically truncate strings (and probably add a configurable indicator like ...) that exceed that length.
+--------------+----------+----------------+
| 字段名称 | 字段描述 | 字段补充说明 |
+==============+==========+================+
| id | 角色id值 | |
+--------------+----------+----------------+
| name | 角色名称 | |
+--------------+----------+----------------+
| description | 角色描述 | |
+--------------+----------+----------------+
| created_time | 创建时间 | 由系统自动更新 |
+--------------+----------+----------------+
| updated_time | 更新时间 | 由系统自动更新 |
+--------------+----------+----------------+
| whatplat | 哪个平台 | |
+--------------+----------+----------------+
| ext_info | 扩展信息 | |
+--------------+----------+----------------+
+--------------+-------------------+-----------------------------+
| Field Name | Field Description | Field Desc Complementation |
+==============+===================+=============================+
| id | role id | |
+--------------+-------------------+-----------------------------+
| name | role name | |
+--------------+-------------------+-----------------------------+
| description | role description | |
+--------------+-------------------+-----------------------------+
| created_time | created time | updated by db automatically |
+--------------+-------------------+-----------------------------+
| updated_time | updated time | updated by db automatically |
+--------------+-------------------+-----------------------------+
| whatplat | what platform | |
+--------------+-------------------+-----------------------------+
| ext_info | extend infomation | |
+--------------+-------------------+-----------------------------+
FORMAT_CLEAN doesn't technically require padding of the final cell, since each row has a newline at the end. This can be desirable to avoid ridiculous output when the final cell differs in width by hundreds of characters. I'm unsure if this would be preferable in all situations though.
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.