GithubHelp home page GithubHelp logo

andrewradev / sideways.vim Goto Github PK

View Code? Open in Web Editor NEW
481.0 4.0 9.0 267 KB

A Vim plugin to move function arguments (and other delimited-by-something items) left and right.

Home Page: http://www.vim.org/scripts/script.php?script_id=4171

License: MIT License

Ruby 50.99% Vim Script 49.01%
cursor arguments lists refactoring text-manipulation vim-plugin text-objects

sideways.vim's Introduction

GitHub version Build Status

Usage

The plugin defines two commands, :SidewaysLeft and :SidewaysRight, which move the item under the cursor left or right, where an "item" is defined by a delimiter. As an example:

def function(one, two, three):
    pass

Placing the cursor on "two" and executing :SidewaysLeft, the "one" and "two" arguments will switch their places, resulting in this:

def function(two, one, three):
    pass

In this case, the delimiter is a comma. The plugin currently works with various other cases and it's intended to make the process configurable. While this particular example is in python, this should work for arguments in many different languages that use round braces to denote function calls.

For ruby and eruby, it detects method calls without braces as well:

link_to user_registration_path, 'Something'
# changes to:
link_to 'Something', user_registration_path

Apart from functions, it works for square-bracket lists in dynamic languages:

list = [one, [two, four, five], three]

If you experiment with this example, you'll find that you can move the entire second list around, as long as the cursor is on one of the inner brackets. The plugin takes into consideration nested structures.

It also works for multiline lists. Try experimenting with this example:

<div class="example"
     style="color: red;"
     something="other">
  Example
</div>

It's highly recommended to map the two main commands to convenient keys. For example, mapping them to <c-h> and <c-l> would look like this:

nnoremap <c-h> :SidewaysLeft<cr>
nnoremap <c-l> :SidewaysRight<cr>

The plugin also provides the commands :SidewaysJumpLeft and :SidewaysJumpRight, which move the cursor left and right by items.

Other things that sideways works for:

CSS declarations:

a { color: #fff; background: blue; text-decoration: underline; }

Lists within CSS declarations:

border-radius: 20px 0 0 20px;

HTML attributes:

<input name="one" id="two" class="three" />

Handlebars components:

{{parent/some-component one=two three="four" five=(action 'six')}}

Cucumber tables:

Examples:
  | input_1 | input_2 | button | output |
  | 20      | 30      | add    | 50     |
  | 2       | 5       | add    | 7      |
  | 0       | 40      | add    | 40     |

Rust template arguments:

let dict = Hash<String, Vec<String>>::new();

Rust return type (a special case since there's always just one, useful as a text object):

fn example() -> Result<String, String> {

Go lists:

[]string{"One", "Two", "Three"}

C++ templates:

/*
 * Relies on "<" being surrounded by non-whitespace, or considers it a
 * comparison. Parsing C++ is tricky.
 */
std::unordered_map<k, v>()

Javascript-like objects:

dict = {one: 1, two: 2, three: 3}

OCaml lists:

let xs = [1;2;3]

LaTeX align/tabular:

\begin{tabular}{ll}
  a & b \\
  c & d
\end{tabular}

LaTeX equations:

\[ e^{i \pi} + 1 = 0 \]
\[e^x = \sum_{n = 0}^{\infty} \frac{x^n}{n!}\]

Typescript enum values:

interface Status {
  code: 200 | 404 | 500;
}

Python imports and for loops:

from some_package import Foo, Bar

for value, index in enumerate(items):
    pass

The plugin is customizable -- take a look at :help sideways-customization for instructions on how to implement support for other kinds of lists.

Bonus functionality

Text objects

The plugin's machinery makes it easy to implement an "argument" text object. There are two mappings provided:

<Plug>SidewaysArgumentTextobjA
<Plug>SidewaysArgumentTextobjI

These are the outer and inner text objects, respectively. To use them, you need to create mappings in your configuration files. Something like this:

omap aa <Plug>SidewaysArgumentTextobjA
xmap aa <Plug>SidewaysArgumentTextobjA
omap ia <Plug>SidewaysArgumentTextobjI
xmap ia <Plug>SidewaysArgumentTextobjI

This will map the "a" text object to operate on an "argument". So, you can perform daa to delete an argument, cia to change an argument, and so on. See :help text-objects for more information.

Also, a useful plugin to use alongside sideways is fieldtrip. This defines a submode for sideways.vim.

Adding items

The plugin defines mappings to add new items to the list as well. There's four of them that mirror the i, a, I, and A built-in keybindings:

<Plug>SidewaysArgumentInsertBefore
<Plug>SidewaysArgumentAppendAfter
<Plug>SidewaysArgumentInsertFirst
<Plug>SidewaysArgumentAppendLast

However, they're not mapped by default and you need to pick ones that are convenient for you. As an example:

nmap <leader>si <Plug>SidewaysArgumentInsertBefore
nmap <leader>sa <Plug>SidewaysArgumentAppendAfter
nmap <leader>sI <Plug>SidewaysArgumentInsertFirst
nmap <leader>sA <Plug>SidewaysArgumentAppendLast

The mnemonic in this case would be leader-"sideways"-action. Given the following simple example in ruby:

function_call(one, two, three)

With the cursor on "two", you can insert a new argument before the current item by using <Plug>SidewaysArgumentInsertBefore:

function_call(one, NEW, two, three)

Add an item after the current one by using <Plug>SidewaysArgumentAppendAfter:

function_call(one, two, NEW, three)

Prepend an item to the start of the list with <Plug>SidewaysArgumentInsertFirst:

function_call(NEW, one, two, three)

Push an item at the end with <Plug>SidewaysArgumentAppendLast:

function_call(one, two, three, NEW)

This should work for all lists that are supported for the plugin, including HTML attributes, semicolon-separated CSS declarations, etc. If each existing list item is on a separate line (and there's at least two), the plugin assumes the new item should be on a new line as well:

function_call(
  one,
  two,
  three
)

# Append an item at the end:
function_call(
  one,
  two,
  three,
  NEW
)

Again, these mappings are not created by default -- copy the suggested ones to your vimrc, or create your own.

If you set g:sideways_add_item_cursor_restore to 1 and your vim has the +textprop feature, the plugin will jump back to where you triggered the mapping when you leave insert mode.

Note, however, that this relies on the InsertLeave autocommand, so if you exit insert mode via Ctrl+C (which doesn't trigger it), it won't jump until the next time you leave insert mode normally. If exiting via Ctrl+C is a part of your workflow, it's recommended you keep this setting off.

sideways.vim's People

Contributors

andrewradev avatar geneotech avatar ivangarciabernal avatar jdsutherland avatar noahfrederick avatar phongnh avatar thinca avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

sideways.vim's Issues

Support for [a; b]

[a; b; c; d] syntax is generally used in OCaml (or only OCaml) and when I try to use it it does not work. Any solution?

A case that `sideways.vim` ignores

Hi,
Sideways is realy a great plugin that saves me a lot of time.
It works as what I expected most of the time.

But it ignores a case that happens in my daily work.

a, b, c = 1, 2, 3

Sideways can't move a, b or c left or right.
There is the same issue with 1, 2 or 3.

Thanks in advance if you can consider such case!

Moving last argument when there others with omitted type in Go

Suppose we have the function foo defined as follows:

func foo(a string, b string) { ... }

Given that both arguments are of the same type we could omit the type declaration of a:

func foo(a, b string) { ... }

In that case when moving any of the arguments, a becomes the last argument without declared type, which is invalid Go code:

func foo(b string, a) { ... }

Does not work correctly in typescript

Shifting does not work correctly in typescript when types are specified.

This works fine:

function foo(a, b, c) {
    console.log(a, b)
}

This doesn't:

function foo(a: number, b: number, c: number) {
    console.log(a, b)
}

Using :SidewaysRight or :SidewaysLeft on the first argument 'a' works as expected.
Using :SidewaysRight or :SidewaysLeft on any other argument, does not shift anything, but always places the cursor to the next type definition to the left.

E.g.:
Cursor is on 'b' + :SidewaysRight => Nothing is shifted, cursor shifts to 'number' after 'a'.

Unbalanced parens make SidewaysArgumentTextobjI/A jump to unrelated line

Several times I've had sideways select text that doesn't include my cursor position. I think it would make more sense to do nothing than jump to another part of the buffer. I've found a reliable and small repro case:

EditorGUI.BeginProperty(position, label, property);
{
    SerializedProperty joint = property.serializedObject.FindProperty("Bone"); // will jump to here

    Debug.Log(string.Format("1) Found a good one: {0}"), joint); // selecting from here
}
EditorGUI.EndProperty();

Do:

/joint)
vi,

(i, is SidewaysArgumentTextobjI)

Result:

The SerializedProperty line is selected.

va, selects the S in SerializedProperty and the space before it.

The only case I can think of where sideways selects something that doesn't include my cursor position is on a comma and the next argument is on the following line (but I'd argue it should select the preceeding argument). Would it make sense to limit the textobjs to require inclusion of the cursor position?

Using 2d5cd2b on Gvim 8.0.596 Win64

Shifting elements in array literals inside function arguments broken

Shifting nested elements does not work when a bracketed list is inside a parenthesis list:

  foo([ 'bar', 'baz', 'quux' ]);

When invoking :SidewaysLeft with the cursor over 'baz', I would expect it to shift to the left in the array literal, but the cursor is just placed over the opening bracket and nothing moves.

Love the plugin, keep up the good work!

Bug when &selection=exclusive

The ReplaceMotion at https://github.com/AndrewRadev/sideways.vim/blob/master/autoload/sideways/util.vim#L92 does not take into account when &selection is exclusive.

Steps to reproduce: just set selection=exclusive, and try SidewaysRight.

This is because gov is assuming the visual selection is inclusive. Selection should be set to inclusive before doing ReplaceMotion:

  let old_selection = &selection
  let &selection = 'inclusive'
  call sideways#util#ReplaceMotion(start_byte.'gov'.end_byte.'go', a:text)
  let &selection = old_selection

I'm not sure about the exact architecture of the plugin, and it should be possible to refactor the selection setting so it is only called once per :SidewaysRight/Left call.

:Sideways* failed when `multiline lists`

for example: cursor on line#2 e.g 'f' of 'formid', then :SidewaysRight, returned items is [], err reported out of index.

<form
id="formid"
name="myform"
method='post'
onsubmit="return checkUser();">

// looks it failed if start item had no 'tab' or 'space' indent -and- cursor on that item ..

Moving conditionals around

Lo again,

I've quite often found myself wanting to move conditionals around. They're parse very similarly to function arguments, but are delimited by && and || rather than commas. You reckon it's possible to get Sideways.vim working with those too?

Merci in advance!

Shortcut to add new item (param/attribute)

I think it's useful to have a shortcut to add a new item (for me, generally a new param or an xml-like attribute). e.g. (cursor at one):

dict = {█one: 1, two: 2, three: 3}

nnoremap ,aa :SidewaysJumpRight<cr>i<space><left>,<left> results in:

dict = {one: 1,, two: 2, three: 3}

This generally works but has a few issues:

  1. It wraps around if at the tail item.
    e.g. (cursor on foo)
    const fn = (█foo) =>
    results in
    const fn = (█, foo) =>
    instead of
    const fn = (foo, █) =>

  2. Not everything uses , delimiters (e.g. html/css/jsx/cucumber tables/ocaml/probably others)
    A workaround for html/css/jsx would be to use a separate map that doesn't insert , like:
    nnoremap ,as :SidewaysJumpRight<cr>i<space><left>

For 1., one solution might be to add an option to disable wraparound.

For 2., I suspect it might be a bit of work to get a single command working across all supported filetypes so I'm not sure it's worth the effort compared to simply making additional mappings.

I wish vim allowed a with text objects.

Anyway, I just wanted to see if there is any interest or possibly find out if I'm overlooking something and it can be done more easily. Thanks for the great plugin.

How to add custom definitions without forking this plugin?

HI, thanks for the awesome plugin.

I'm trying to add a new custom rule to swap the case options in go's switch-case statements:

case foo, bar, baz:

So I put these in my vimrc, but with no luck:

call plug#begin('~/.vim/plug')
    Plug 'AndrewRadev/sideways.vim'
call plug#end()

autocmd! FileType go let b:sideways_definitions = [
    \ {
    \     'start':     'case ',
    \     'end':       ':',
    \     'delimiter': ',\s*',
    \     'brackets':  ['([''"', ')]''"'],
    \ },
\ ]

I know there're sane defaults defined in sideways.vim/plugin/sideways.vim, and they seem to override my custom setup, as the plugin code in &runtimepath is loaded after .vimrc:

:autocmd FileType go
--- Autocommands ---
FileType
    go        let b:sideways_definitions = [   {     'start':     'case ',     'end':       ':',     'delimiter': ',\s*',     'brackets':  ['([''"', ')]''"'], }, ]
    go        let b:sideways_definitions = [   {     'start':     '{\_s*',     'end':       '\_s*}',     'delimiter': ',\s*',   'brackets':  ['([''"', ')]''"'],   }, ]
Press ENTER or type command to continue

:echo b:sideways_definitions
[{'end': '\_s*}', 'brackets': ['([''"', ')]''"'], 'start': '{\_s*', 'delimiter': ',\s*'}]

Now I've create a "plugin" with my sideways definitions, and put it at the end of my &rtp. But I guess the customization process could be made easier, so I'm looking for idea and suggestions. Thanks.

Edit: the custom g:sideways_definitions in vimrc is also overridden by the defaults, so I've changed the title.

Using as motion

Hey,

Thanks for writing plugins with tests!

Any idea how to use Sideways's argument text objects as Vim motions? So instead of deleting or changing the argument you're on, you'd be able to say "delete the next two arguments"? I'm getting quite tired of counting commas manually and doing d2f,. :)

conflict with coc.nvim in nvim

Hi, I am afraid I don't have as much information as I would like to have, but I've been making slow progress on this issue and I think I have enough to be able to report now.

Basically when using coc.nvim, certain plugins I was using cause its diagnostic signs to become stale and linger around. This is, as you can imagine, completely disruptive to development workflow.

I was able to bisect my plugins down to a group of 4 plugins that when any of them individually are enabled (along with the entire rest of my set of plugins) I experience this behavior with coc.nvim. They are:

" Plug 'AndrewRadev/sideways.vim'
" Plug 'AndrewRadev/linediff.vim'
" Plug 'AndrewRadev/splitjoin.vim'
" Plug 'AndrewRadev/inline_edit.vim'

Once all 4 are commented out I no longer get the lingering stale signs in typescript TSX files I'm working with.

Interestingly Plug 'AndrewRadev/switch.vim' is no problem. I still have it enabled.

One of the problems with this bug report is that I cannot even reproduce this lingering signs issue with most other syntaxes. So it may even theoretically be a very specific bug with neovim AND coc.nvim AND typescript tsx...

(with regular vim (which i have not used in a while so i lend less weight to this data) which I just re-compiled on master, the problem does not surface!)

I was wondering if we could brainstorm what config is being set in these 4 plugins but not switch which may help point to the root problem.

React

Is possible configure the plugin to work with react, I have this, but doesn't work in the attributes of the tags

import React from 'react';
import uid from 'uid';

const CourseAddForm = (props) => (
  <form onSubmit={props.onAddCourse}>
    <input type="text" placeholder="Nombre del curso" name="name"/>
    <input type="text" placeholder="Profesor" name="teacher"/>
    <input type="hidden" name="id" value={Math.floor( Math.random() * 100 )}/>
    <input type="submit" value="Guardar"/>
  </form>
);

export default CourseAddForm;


Feature request: Bash Scripts

It would be nice to have bash support (I suppose something similar to html would work). I'm trying to use customization but it would be nice to have official support :)

Error in macvim

In macvim, when trying the basic sideways command, I get:

Error detected while processing function sideways#MoveRight..sideways#Parse:
line 7:
E117: Unknown function: sideways#parsing#Parse
E15: Invalid expression: sideways#parsing#Parse(definitions)

Doesn't work when the delimiter starts on a new line

I'm trying to make this plugin work on chained methods in PHP, with the following configuration:

autocmd FileType php let b:sideways_definitions = [{
      \   'start': '\(\w\+::\|\$\w\+->\)\_s*',
      \   'end': ';',
      \   'delimiter': '\_s*->\_s*',
      \   'brackets':  ['(', ')'],
      \ }]

On a single line it works fine. It also works when the delimiter is at the end of a line, like this:

Route::get('/')->
    as('home')->
    middleware('web');

But when the delimiter starts on a new line (like you normally would with method chaining), it does not work.

Route::get('/')
    ->as('home')
    ->middleware('web');

As an example, it also doesn't work when you try it out on regular functions:

foo(bar
   ,baz
   ,fizz)

It looks like it has to do something with this part here, but I can't really figure out a way to make it work.

Unmatched single quotes make SidewaysArgumentTextobjI jump to unrelated line

Similar to #24.

If I type some text and use Sideways to add quotes, it fails when the text has an unmatched quote (single or double) and later in the file there's a matching quote.

With file test.cs:

public class Modifier
{
    public static bool Test()
    {
        Debug.Log(this unmatched quote ' breaks surrounding text with quotes, this);
        return true;
    }

    // because of this unmatched quote '

}

omap i, <Plug>SidewaysArgumentTextobjI
0
/this unmatched
normal nsi,"

I guess it's interpreting ' breaks surrounding text with quotes, this); as a string that continues past the end of the line. My syntax highlighting (nickspoons/vim-cs) doesn't, but maybe sideways has its own way to determine what's a string?

Initially found on 01bcf0f, but also reproduced on 9dd871e.

space as separator

Is it possible to provide some config with additional separators? In Haskell we are using space as separator between function and argument, example:

add x y = x + y

atm if I'm trying to apply :SidewaysRight to x - it's not working

Option to disable looping

Hey Andrew,

Would you be amenable to including an option to disable looping? I would like to build functionality that is actually a combination of two of your plugins though it would require the result of sideways#MoveLeft() and sideways#MoveRight() to return zero if they are on the first or last arguments. I'm happy to take on the work myself if so.

On a different note, thank you so much for all your great plugins. I am a long time user of splitjoin (looks like I added it back in 2015) but for some reason didn't branch out into your other work much until recently. Deleft, whitespaste, and sideways are all amazing! Perhaps you have other gold but have not looked yet. I also enjoy your YouTube videos. In any event, thanks for all your hard work!

Andrew

No license for this repo

Could you please add a license to this repo (e.g. MIT or Vim license)?

Not having a license can prevent people who have corporate policies around only using licensed software from being able to use this great plugin.

Doesn't seem to detect last argument

I'm seeing an issue where sideways doesn't recognise the last argument/item. For example if I have this code:

[ 1, 2, 3 ]

and I put my cursor on 1 and execute :SidewaysRight, I get

[ 2, 1, 3 ]

as expected. But if I put my cursor back on 1 and execute :SidewaysRight again, I get

[ 1, 2, 3 ]

but it should be [ 2, 3, 1 ], shouldn't it? Am I doing something wrong?

Tested with both JS and Ruby files.

More Generic

It's not an issue as such, more a suggestion. I like this plugin but I'm wondering why it cares about what's before the block boundary (for example, the opening parenthesis in "function( foo, bar, baz)"). The first thing I tested the plugin with was this, and it didn't work:

my ( $self, $foo, $bar ) = @_;

I'd have thought it would be a lot easier to write if it didn't care what was outside of the block. In fact, why care about boundaries at all? Why not have it just move the bits around delimited commas in, for example, this: "foo, bar, baz"?

c++ template parameters are not handled properly

I made a change to fix this. Before I submitted a PR, I realized that it would cause problems when '>' and '<' were used as comparators inside of an argument.

Is there any acceptable way to distinguish between comparators and angle brackets? I think a 100% correct solution would require a full parse of the c++ code. I'm just wondering if there is a approximation that is better than just ignoring templates altogether.

SidewaysJump* little issues

  1. When I have this line of code (cursor is ^):
= f.text_field :email, autofocus: true, class: "form-control", placeholder: "Email", :"ng-model"=>'email', :'ng-change'=>'detect2factorAuth()'
---^

And I execute :SidewaysJumpRight it doesn't take me to the next argument. Is this by purpose?
2)
When I have this long line of code (cursor is ^):

= f.text_field :email, autofocus: true,
                     class: "form-control", placeholder: "Email", :"ng-model"=>'email',
----------------------^
                     :'ng-change'=>'detect2factorAuth()'

And I execute :SidewaysJumpRight it also doesn't work. In this case :Sideways* also doesn't work.

I understand that this maybe is an implementation difficulty.

Make :SidewaysRight (etc) take a count?

Thanks for writing this, it's a huge timesaver already!

Is there a way for me to make Sideways bindings take a count? eg, if I bind gs to :SidewaysRight, using 2gs to do:

(hello, world, today) -> (world, today, hello)

It would also be awesome if it could support repeat.vim (https://github.com/tpope/vim-repeat), so you can use . to repeat swaps.

Thanks again!

Empty Cell

Cannot switch one cell to empty one in Cucumber, Markdown, Vimwiki tables.
One solution on any of these filetypes should work in the others

More targets than List items

when sideways#parsing#Parse return []:

Error detected while processing function sideways#MoveLeft:
line    1:
E688: More targets than List items
line    2:
E121: Undefined variable: items
E116: Invalid arguments for function empty(items)
E15: Invalid expression: empty(items)
...

sideways.vim\autoload\sideways\parsing.vim, line 38:

    return [definition []]

instead.

Allow nested swapping

For example, if I have this:

foo(1, 2, bar(3, 4))

if I have the cursor on 3 or 4 it will switch these as the parameters of bar, so I would have: foo(1, 2, bar(4, 3)) but anywhere else, it would work for foo.

end parenthesis detection error.

if i do such a call:

   foo(bar, baz(foobar(), foobaz))

and try to move bar right, i get

   foo(baz(foobar(), bar, foobaz))

This plugin can save quite some time there and there, keep up the good work :)

Support class option hash for eruby

It'd be nice if #41 worked for option hashes in eruby:

<li><%= link_to 'Home', '#', class: 'one two three' %></li>

I tried implementing this myself:

let b:sideways_definitions = [
      \   {
      \     'start':     '<%=\=\s*\%(\k\|\.\|::\)*\k\{1,} ',
      \     'end':       '\s*%>',
      \     'delimiter': ',\s*',
      \     'brackets':  ['([''"', ')]''"'],
      \   },
      \   {
        \     'skip_syntax':             [],
        \     'start':                   "\v<class:\s?'",
        \     'end':                     "'",
        \     'delimited_by_whitespace': 1,
        \     'brackets':                ['', ''],
        \   },
      \   sideways#html#Definition('tag_attributes',      { 'brackets': ['"''<', '"''>'] }),
      \   sideways#html#Definition('double_quoted_class', { 'brackets': ['<', '>'] }),
      \   sideways#html#Definition('single_quoted_class', { 'brackets': ['<', '>'] }),
      \   sideways#html#Definition('double_quoted_style', { 'brackets': ['<', '>'] }),
      \   sideways#html#Definition('single_quoted_style', { 'brackets': ['<', '>'] }),
      \ ]

but the existing seemed to take precedence. I'm guessing the regex:

'start': '<%=\=\s*\%(\k\|\.\|::\)*\k\{1,}`

would have to negative lookahead for class:?

Move things in curly braces

Hey,

Given that Sideways.vim already supports moving elements of arrays ([1, 2, 3]), how about supporting the same in curly braces ({a: 1, b: 2}) ? Plenty of languages use those for object/hashmap literals and it'd be convenient to move keys around. ;-)

This might, though, make moving those whole objects themselves left and right a little more difficult, but that's a different problem to solve as it also affects how to move a whole array around when the cursor is in that array.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.