Compare commits

...

5 Commits

Author SHA1 Message Date
Enno
8a2ec348e1
Merge bea8f291bc into 770a4138b4 2024-12-18 16:19:19 -03:00
Boris Verkhovskiy
770a4138b4
Lint frontmatter (#5218) 2024-12-18 09:38:58 -07:00
Boris Verkhovskiy
4d7ecfbbf7 [brainfuck] rename frontmatter key
All checks were successful
Trigger site build / deploy (push) Has been skipped
CI / lint (push) Successful in 20s
2024-12-18 08:14:10 -07:00
Konfekt
bea8f291bc correct vim9script syntax 2024-12-16 20:59:36 +01:00
Konfekt
8083755456 add vim9script as translation of @hiphish 's legacy vimscript file 2024-12-16 18:12:54 +01:00
20 changed files with 624 additions and 81 deletions

View File

@ -3,4 +3,3 @@
- [ ] Pull request touches only one file (or a set of logically related files with similar changes made)
- [ ] Content changes are aimed at *intermediate to experienced programmers* (this is a poor format for explaining fundamental programming concepts)
- [ ] If you've changed any part of the YAML Frontmatter, make sure it is formatted according to [CONTRIBUTING.md](https://github.com/adambard/learnxinyminutes-docs/blob/master/CONTRIBUTING.md)
- [ ] Yes, I have double-checked quotes and field names!

View File

@ -11,8 +11,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.13'
- run: pip install -r lint/requirements.txt
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
- run: gem install mdl
- run: mdl . --ignore-front-matter -r MD003,MD011,MD023,MD027,MD028,MD035,MD037,MD038,MD039,MD047
- name: Files are UTF-8
run: ./lint/encoding.sh .
- name: Lint Markdown
run: mdl . --ignore-front-matter -r MD003,MD011,MD023,MD027,MD028,MD035,MD037,MD038,MD039,MD047
- name: Lint frontmatter
run: ./lint/frontmatter.py .

View File

@ -31,13 +31,6 @@ review them more effectively and/or individually.
language in question.
* Keep articles succinct and scannable. We all know how to use Google here.
* **Use UTF-8**
* For translations (or EN articles with non-ASCII characters) please ensure
your file is UTF-8 encoded.
* Leave out the byte-order-mark (BOM) at the start of the file (in Vim, use
`:set nobomb`).
* You can check if the file contains a BOM on Linux/Unix systems by running
`file language.html.markdown` You will see this if it uses a BOM:
`UTF-8 Unicode (with BOM) text`.
### Header configuration
@ -48,29 +41,32 @@ called frontmatter.
The following fields are necessary for English articles about programming
languages:
* **name** The human-readable name of the programming language
* **contributors** A list of [author, URL] lists to credit
* `name`: The human-readable name of the programming language
* `contributors`: A list of [*author*, *URL*] lists to credit, *URL* is optional
Other fields:
* **category**: The category of the article. So far, can be one of *language*,
* `category`: The category of the article. So far, can be one of *language*,
*tool* or *Algorithms & Data Structures*. Defaults to *language* if omitted.
* **filename**: The filename for this article's code. It will be fetched, mashed
* `filename`: The filename for this article's code. It will be fetched, mashed
together, and made downloadable.
Translations should also include:
* `translators`: A list of [*translator*, *URL*] lists to credit, *URL* is optional
Non-English articles inherit frontmatter values from the English article (if it exists)
but you can overwrite them.
Here's an example header for Ruby:
```yaml
*--
---
name: Ruby
filename: learnruby.rb
contributors:
- ["Doktor Esperanto", "http://example.com/"]
- ["Someone else", "http://someoneelseswebsite.com/"]
*--
---
```
### Syntax highlighter

2
bf.md
View File

@ -1,6 +1,6 @@
---
name: BF
learn_x_in_y_name: brainfuck
where_x_eq_name: brainfuck
filename: bf.bf
contributors:
- ["Prajit Ramachandran", "http://prajitr.github.io/"]

View File

@ -2,7 +2,7 @@
filename: learngroovy-ca.groovy
contributors:
- ["Roberto Pérez Alcolea", "http://github.com/rpalcolea"]
translations:
translators:
- ["Xavier Sala Pujolar", "http://github.com/utrescu"]
---

View File

@ -1,7 +1,7 @@
---
contributors:
- ["Dan Turkel", "http://danturkel.com/"]
translators :
translators:
- ["Frederik Ring", "https://github.com/m90"]
- ["Philipp Fischbeck", "https://github.com/PFischbeck"]
filename: markdown-de.md

View File

@ -3,10 +3,9 @@ contributors:
- ["Joao Marques", "http://github.com/mrshankly"]
- ["Dzianis Dashkevich", "https://github.com/dskecse"]
- ["Ryan Plant", "https://github.com/ryanplant-au"]
translator:
translators:
- ["Adrian Carrascal", "https://github.com/acarrascalgarcia"]
filename: learnelixir-es.ex
---
Elixir es un lenguaje funcional moderno construido sobre la máquina virtual de Erlang.

View File

@ -2,9 +2,8 @@
filename: LearnGit-es.txt
contributors:
- ["Jake Prather", "http://github.com/JakeHP"]
translator:
translators:
- ["Raúl Ascencio", "http://rscnt.github.io"]
---
Git es un sistema de control de versiones distribuido diseñado para manejar

View File

@ -4,10 +4,11 @@ contributors:
- ["Dzianis Dashkevich", "https://github.com/dskecse"]
- ["Ryan Plant", "https://github.com/ryanplant-au"]
- ["Ev Bogdanov", "https://github.com/evbogdanov"]
translator:
translators:
- ["Timothé Pardieu", "https://github.com/timprd"]
filename: learnelixir-fr.ex
---
Elixir est un langage de programmation fonctionnel moderne reposant sur la machine virtuelle BEAM, qui héberge aussi Erlang.
Il est totalement compatible avec Erlang mais dispose d'une syntaxe plus agréable et apporte de nouvelles fonctionnalités.

View File

@ -1,6 +1,5 @@
---
name: Groovy
filename: learngroovy.groovy
contributors:
- ["Roberto Pérez Alcolea", "http://github.com/rpalcolea"]
filename: learngroovy.groovy

View File

@ -1,7 +1,7 @@
---
contributors:
- ["Brett Taylor", "https://github.com/glutnix"]
translator:
translators:
- ["Agostino Fiscale", "https://github.com/agostinofiscale"]
filename: LearnComposer-it.sh
---

30
lint/encoding.sh Executable file
View File

@ -0,0 +1,30 @@
#!/bin/bash
check_encoding() {
file="$1"
encoding=$(file -b --mime-encoding "$file")
# Check if the encoding is neither UTF-8 nor US-ASCII
if [[ "$encoding" != "utf-8" && "$encoding" != "us-ascii" ]]; then
# Print the file path and encoding
echo "Error: $file has encoding $encoding, which is not utf-8 or us-ascii"
return 1
fi
# Check for UTF-8 BOM
if [[ "$encoding" == "utf-8" ]]; then
if head -c 3 "$file" | cmp -s <(echo -ne '\xEF\xBB\xBF'); then
echo "Error: $file contains a UTF-8 BOM"
return 1
fi
fi
return 0
}
export -f check_encoding
# Default to current directory if no argument is given
directory="${1:-.}"
find "$directory" -type f -name "*.md" -print0 | xargs -0 -P 8 -I {} bash -c 'check_encoding "$@"' _ {}

120
lint/frontmatter.py Executable file
View File

@ -0,0 +1,120 @@
#!/usr/bin/env python3
import re
from pathlib import Path
import yaml
import yamllint.config
import yamllint.linter
def extract_yaml_frontmatter(file_path):
"""Extracts YAML front matter from a Markdown file."""
with open(file_path, "r", encoding="utf-8") as file:
content = file.read()
matches = re.match(r"^(---\s*\n.*?\n)---\n", content, re.DOTALL)
if matches:
return matches.group(1)
return None
yaml_config = yamllint.config.YamlLintConfig(
"""{
extends: relaxed,
rules: {
commas: disable,
trailing-spaces: disable,
indentation: disable,
line-length: disable,
empty-lines: disable
}
}"""
)
def lint_yaml(yaml_content):
"""Lints YAML content using yamllint by sending it to stdin."""
problems = []
for p in yamllint.linter.run(yaml_content, yaml_config):
problems.append(f"{p.line}:{p.column} {p.desc} ({p.rule})")
return "\n".join(problems)
def validate_yaml_keys(yaml_content, allowed_keys):
"""Validates that the YAML content contains only the specified keys."""
try:
data = yaml.safe_load(yaml_content)
if not data:
return "Empty YAML front matter."
extra_keys = set(data.keys()) - set(allowed_keys)
if extra_keys:
return f"Invalid keys found: {', '.join(extra_keys)}"
for key, value_type in allowed_keys.items():
if key in data:
if not isinstance(data[key], value_type):
return f"Invalid type for key '{key}': expected {value_type.__name__}, got {type(data[key]).__name__}"
if isinstance(data[key], list):
for item in data[key]:
if not isinstance(item, list):
return f"Invalid type for item in key '{key}': expected list, got {type(item).__name__}"
elif not item:
return f"Invalid item in key '{key}': found empty list"
elif not isinstance(item[0], str):
return f"Invalid type for item[0] in key '{key}': expected str, got {type(item[0]).__name__}"
elif len(item) == 2 and not isinstance(item[1], str):
return f"Invalid type for item[1] in key '{key}': expected str, got {type(item[1]).__name__}"
elif len(item) > 2:
return f"Invalid length for item in key '{key}': expected 1 or 2, got {len(item)}"
except yaml.YAMLError as e:
return f"Error parsing YAML: {e}"
return ""
def process_files(path):
"""Processes either a single file or all Markdown files in a directory."""
if path.is_dir():
pathlist = path.rglob("*.md")
else:
pathlist = [path]
has_error = False
allowed_keys = {
"name": str,
"where_x_eq_name": str,
"category": str,
"filename": str,
"contributors": list,
"translators": list,
}
for path in pathlist:
yaml_content = extract_yaml_frontmatter(path)
if yaml_content:
lint_result = lint_yaml(yaml_content)
key_validation = validate_yaml_keys(yaml_content, allowed_keys)
if lint_result or key_validation:
if has_error: # don't prepend newline to first error
print()
print(path)
if lint_result:
print(lint_result)
if key_validation:
print(key_validation)
has_error = True
return has_error
def main(path_input):
"""Determines if the input is a directory or a file and processes accordingly."""
path = Path(path_input)
if not path.exists():
print(f"Error: {path_input} does not exist.")
return 1
return process_files(path)
if __name__ == "__main__":
import sys
path_input = sys.argv[1] if len(sys.argv) > 1 else "."
has_error = main(path_input)
sys.exit(1 if has_error else 0)

2
lint/requirements.txt Normal file
View File

@ -0,0 +1,2 @@
yamllint
pyyaml

View File

@ -3,7 +3,7 @@ contributors:
- ["Joao Marques", "http://github.com/mrshankly"]
- ["Dzianis Dashkevich", "https://github.com/dskecse"]
- ["Ryan Plant", "https://github.com/ryanplant-au"]
translator:
translators:
- ["Ev Bogdanov", "https://github.com/evbogdanov"]
filename: learnelixir-ru.ex
---

View File

@ -1,32 +0,0 @@
#!/usr/bin/env ruby
require 'charlock_holmes'
$file_count = 0;
markdown_files = Dir["./**/*.html.markdown"]
markdown_files.each do |file|
begin
contents = File.read(file)
detection = CharlockHolmes::EncodingDetector.detect(contents)
case detection[:encoding]
when 'UTF-8'
$file_count = $file_count + 1
when 'ISO-8859-1'
$file_count = $file_count + 1
when /ISO-8859/
puts "Notice: #{file} was detected as #{detection[:encoding]} encoding. Everything is probably fine."
$file_count = $file_count + 1
else
puts "WARNING #{file} was detected as #{detection[:encoding]} encoding. Please save the file in UTF-8!"
end
rescue Exception => msg
puts msg
end
end
files_failed = markdown_files.length - $file_count
if files_failed != 0
puts "FAILURE!!! #{files_failed} files were unable to be validated as UTF-8!"
puts "Please resave the file as UTF-8."
exit 1
else
puts "Success. All #{$file_count} files passed UTF-8 validity checks."
exit 0
end

View File

@ -1,21 +0,0 @@
#!/usr/bin/env ruby
require 'yaml';
$file_count = 0;
markdown_files = Dir["./**/*.html.markdown"]
markdown_files.each do |file|
begin
YAML.load_file(file)
$file_count = $file_count + 1
rescue Exception => msg
puts msg
end
end
files_failed = markdown_files.length - $file_count
if files_failed != 0
puts "FAILURE!!! #{files_failed} files were unable to be parsed!"
puts "Please check the YAML headers for the documents that failed!"
exit 1
else
puts "All #{$file_count} files were verified valid YAML"
exit 0
end

View File

@ -8,7 +8,6 @@ contributors:
- ["Jason Stathopulos", "http://github.com/SpiritBreaker226"]
- ["Milo Gilad", "http://github.com/Myl0g"]
- ["Adem Budak", "https://github.com/p1v0t"]
filename: LearnGit-tr.txt
---

443
vim9script.md Normal file
View File

@ -0,0 +1,443 @@
---
name: Vim9script
filename: learn9vimscript.vim
contributors:
- ["HiPhish", "http://hiphish.github.io/"]
---
```vim
# ##############
# Introduction
# ##############
# Vim9 script is a modernized version of Vim's scripting language, offering features like variables, functions, and loops.
# Accoding to `:help vim9-differences`, the principal differences from legacy Vim script are as follows:
#
# - Comments start with #, not ": >
# echo "hello" # comment
# - Using a backslash for line continuation is hardly ever needed: >
# echo "hello "
# .. yourName
# .. ", how are you?"
# - White space is required in many places to improve readability.
# - Assign values without `:let` *E1126* , declare variables with `:var`: >
# var count = 0
# count += 3
# - Constants can be declared with `:final` and `:const`: >
# final matches = [] # add to the list later
# const names = ['Betty', 'Peter'] # cannot be changed
# - `:final` cannot be used as an abbreviation of `:finally`.
# - Variables and functions are script-local by default.
# - Functions are declared with argument types and return type: >
# def CallMe(count: number, message: string): bool
# - Call functions without `:call`: >
# writefile(['done'], 'file.txt')
# - You cannot use old Ex commands:
# `:Print`
# `:append`
# `:change`
# `:d` directly followed by 'd' or 'p'.
# `:insert`
# `:k`
# `:mode`
# `:open`
# `:s` with only flags
# `:t`
# `:xit`
# - Some commands, especially those used for flow control, cannot be shortened.
# E.g., `:throw` cannot be written as `:th`. *vim9-no-shorten*
# - You cannot use curly-braces names.
# - A range before a command must be prefixed with a colon: >
# :%s/this/that
# - Executing a register with "@r" does not work, you can prepend a colon or use
# `:exe`: >
# :exe @a
# - Unless mentioned specifically, the highest |scriptversion| is used.
# - When defining an expression mapping, the expression will be evaluated in the
# context of the script where it was defined.
# - When indexing a string the index is counted in characters, not bytes:
# |vim9-string-index|
# - Some possibly unexpected differences: |vim9-gotchas|.
#
# You can run Vim9 script commands in command-line mode or write them to a file and source it in Vim.
# This guide assumes familiarity with ex-commands and focuses on scripting.
# Comments start with #
# The vertical line '|' separates commands
echo 'Hello' | echo 'world!'
# Putting a comment after a command usually works
pwd # Displays the current working directory
# Line continuation is rarely needed
echo "Hello "
.. "world"
echo [1, 2]
echo {
'a': 1,
'b': 2
}
# #######
# Types
# #######
# Numbers
echo 123 # Decimal
echo 0b1111011 # Binary
echo 0173 # Octal
echo 0x7B # Hexadecimal
echo 123.0 # Floating-point
echo 1.23e2 # Floating-point (scientific notation)
# Booleans
echo true # Evaluates to true
echo false # Evaluates to false
# Boolean values from comparison
echo x == y # Equality by value
echo x != y # Inequality
echo x > y # Greater than
echo x >= y # Greater than or equal
echo x < y # Smaller than
echo x <= y # Smaller than or equal
echo x is y # Instance identity
echo x isnot y # Instance non-identity
# Strings
echo 'a' < 'B' # True or false depending on 'ignorecase'
echo 'a' <? 'B' # True
echo 'a' <# 'B' # False
# Regular expression matching
echo "hi" =~ "hello" # Regular expression match
echo "hi" =~# "hello" # Case sensitive
echo "hi" =~? "hello" # Case insensitive
echo "hi" !~ "hello" # Regular expression unmatch
echo "hi" !~# "hello" # Case sensitive
echo "hi" !~? "hello" # Case insensitive
# Boolean operations
echo true && false # Logical AND
echo true || false # Logical OR
echo !true # Logical NOT
echo true ? 'yes' : 'no' # Ternary operator
# Strings
echo "Hello world\n" # Newline
echo 'Hello world\n' # Literal
echo 'Let''s go!' # Two single quotes become one
# String concatenation
echo 'Hello ' .. 'world' # String concatenation
# String indexing
echo 'Hello'[0] # First character
echo 'Hello'[1] # Second character
echo 'Hellö'[4] # Returns a character
# Substrings
echo 'Hello'[:] # Copy of entire string
echo 'Hello'[1:3] # Substring
echo 'Hello'[1:-2] # Substring until second to last character
echo 'Hello'[1:] # Substring with starting index
echo 'Hello'[:2] # Substring with ending index
echo 'Hello'[-2:] # Substring relative to end
# Lists
echo [] # Empty list
echo [1, 2, 'Hello'] # List with elements
echo [1, 2, 'Hello', ] # Trailing comma permitted
echo [[1, 2], 'Hello'] # Nested lists
# List concatenation
echo [1, 2] + [3, 4] # Creates a new list
# List indexing
echo [1, 2, 3, 4][2] # Third element
echo [1, 2, 3, 4][-1] # Last element
# List slicing
echo [1, 2, 3, 4][:] # Shallow copy
echo [1, 2, 3, 4][:2] # Sublist until third item
echo [1, 2, 3, 4][2:] # Sublist from third item
echo [1, 2, 3, 4][:-2] # Sublist until second-to-last item
# Dictionaries
echo {} # Empty dictionary
echo {'a': 1, 'b': 2} # Dictionary literal
echo {'a': 1, 'b': 2, } # Trailing comma permitted
echo {'x': {'a': 1, 'b': 2}} # Nested dictionary
# Indexing a dictionary
echo {'a': 1, 'b': 2}['a'] # Literal index
echo {'a': 1, 'b': 2}.a # Syntactic sugar
# Funcref
echo function('type') # Reference to function type()
echo {x -> x * x} # Anonymous function
# Regular expression
substitute/hello/Hello/
# ###########################
# Implicit type conversions
# ###########################
echo "1" + 1 # Number
echo "1" .. 1 # String
echo "0xA" + 1 # Number
# ###########
# Variables
# ###########
var b:my_var = 1 # Local to current buffer
var w:my_var = 1 # Local to current window
var t:my_var = 1 # Local to current tab page
var g:my_var = 1 # Global variable
# Access special Vim memory like variables
var @a = 'Hello' # Register
var $PATH='' # Environment variable
var &textwidth = 79 # Option
var &l:textwidth = 79 # Local option
var &g:textwidth = 79 # Global option
# Access scopes as dictionaries
echo b: # All buffer variables
echo w: # All window variables
echo t: # All tab page variables
echo g: # All global variables
echo v: # All Vim variables
# Constant variables
const x = 10 # Constant
# Function reference variables
var IsString = {x -> type(x) == type('')} # Global
var isNumber = {x -> type(x) == type(0)} # Local
# Multiple value binding
var [x, y] = [1, 2]
# Assign the remainder to a rest variable
var [mother, father; children] = ['Alice', 'Bob', 'Carol', 'Dennis', 'Emily']
# ##############
# Flow control
# ##############
# Conditional
var condition = true
if condition
echo 'First condition'
elseif another_condition
echo 'Second condition'
else
echo 'Fail'
endif
# Loops
# For-loop
for person in ['Alice', 'Bob', 'Carol', 'Dennis', 'Emily']
echo 'Hello ' .. person
endfor
# Iterate over a nested list
for [x, y] in [[1, 0], [0, 1], [-1, 0], [0, -1]]
echo 'Position: x =' .. x .. ', y = ' .. y
endfor
# Iterate over a range of numbers
for i in range(10, 0, -1)
echo 'T minus' .. i
endfor
# Iterate over the keys of a dictionary
for symbol in keys({'π': 3.14, 'e': 2.71})
echo 'The constant ' .. symbol .. ' is a transcendent number'
endfor
# Iterate over the values of a dictionary
for value in values({'π': 3.14, 'e': 2.71})
echo 'The value ' .. value .. ' approximates a transcendent number'
endfor
# Iterate over the keys and values of a dictionary
for [symbol, value] in items({'π': 3.14, 'e': 2.71})
echo 'The number ' .. symbol .. ' is approximately ' .. value
endfor
# While-loops
var there_yet = true
while !there_yet
echo 'Are we there yet?'
endwhile
# Exception handling
try
source path/to/file
catch /Cannot open/
echo 'Looks like that file does not exist'
catch /.*/
echo 'Something went wrong, but I do not know what'
finally
echo 'I am done trying'
endtry
# ##########
# Functions
# ##########
# Defining functions
def AddNumbersLoudly(x: number, y: number): number
echo 'Adding' .. x .. 'and' .. y
return x + y
enddef
def s:addNumbersLoudly(x: number, y: number): number
echo 'Adding' .. x .. 'and' .. y
return x + y
enddef
# Range functions
def FirstAndLastLine() range
echo [a:firstline, a:lastline]
enddef
# Aborting functions
def SourceMyFile() abort
source my-file.vim
echo 'This will never be printed'
enddef
# Closures
def MakeAdder(x: number)
def Adder(n: number) closure
return n + x
enddef
return funcref('Adder')
enddef
var AddFive = MakeAdder(5)
echo AddFive(3) # Prints 8
# Dictionary functions
def Mylen() dict
return len(self.data)
enddef
var mydict = {'data': [0, 1, 2, 3], 'len': function("Mylen")}
echo mydict.len()
# Alternatively, more concise
var mydict = {'data': [0, 1, 2, 3]}
def mydict.len()
return len(self.data)
enddef
# Calling functions
var animals = keys({'cow': 'moo', 'dog': 'woof', 'cat': 'meow'})
# Call a function for its side effects only
call sign_undefine()
# The call() function
echo call(function('get'), [{'a': 1, 'b': 2}, 'c', 3]) # Prints 3
# Function namespaces
def foo#bar#log(value: string)
echomsg value
enddef
call foo#bar#log('Hello')
# #############################
# Frequently used ex-commands
# #############################
# Sourcing runtime files
runtime plugin/my-plugin.vim
# Defining new ex-commands
command! SwapAdjacentLines normal! ddp
command! -nargs=1 Error echoerr <args>
# Defining auto-commands
autocmd BufWritePost $MYVIMRC source $MYVIMRC
# Auto groups
augroup auto-source
autocmd!
autocmd BufWritePost $MYVIMRC source $MYVIMRC
augroup END
# Executing
var line = 3
execute line .. 'delete'
# Executing normal-mode commands
normal! ggddGp
# Window commands
wincmd L
# ###########################
# Frequently used functions
# ###########################
# Feature check
echo has('nvim')
echo has('python3')
echo has('unix')
echo has('win32')
# Test if something exists
echo exists('&mouse')
echo exists('+mouse')
echo exists('$HOSTNAME')
echo exists('*strftime')
echo exists('**s:MyFunc')
echo exists('bufcount')
echo exists('my_dict["foo"]')
echo exists(':Make')
echo exists("#CursorHold")
echo exists("#BufReadPre#*.gz")
echo exists("#filetypeindent")
echo exists("##ColorScheme")
# Various dynamic values
echo expand('%')
echo expand('<cword>')
echo expand('%:p')
# Type tests
echo type(my_var) == v:t_number
echo type(my_var) == v:t_string
echo type(my_var) == v:t_func
echo type(my_var) == v:t_list
echo type(my_var) == v:t_dict
echo type(my_var) == v:t_float
echo type(my_var) == v:t_bool
echo my_var is v:null
# Format strings
echo printf('%d in hexadecimal is %X', 123, 123)
# #####################
# Tricks of the trade
# #####################
# Source guard
if exists('g:loaded_my_plugin')
finish
endif
var g_loaded_my_plugin = true
# Default values
var greeting = get(g:, 'my_plugin_greeting', 'Hello')
```

View File

@ -4,7 +4,6 @@ contributors:
- ["Aleksey Kholovchuk", "https://github.com/vortexxx192"]
translators:
- ["GengchenXU", "https://github.com/GengchenXU"]
---
**Qt** Qt是一个广为人知的框架用于开发跨平台软件该软件可以在各种软件和硬件平台上运行代码几乎没有变化同时具有本机应用程序的能力和速度。虽然**Qt**最初是用*C*++,但也有其他语言的端口: *[PyQt](../pyqt/)*, *QtRuby*, *PHP-Qt*, 等等.