mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
chore: Another round of style lints fixes (#17519)
Closes #ISSUE Release Notes: - N/A
This commit is contained in:
parent
cfd43572c1
commit
095a08d9c8
10
Cargo.toml
10
Cargo.toml
@ -571,14 +571,18 @@ single_range_in_vec_init = "allow"
|
||||
# There are a bunch of rules currently failing in the `style` group, so
|
||||
# allow all of those, for now.
|
||||
style = { level = "allow", priority = -1 }
|
||||
|
||||
# Temporary list of style lints that we've fixed so far.
|
||||
module_inception = { level = "deny" }
|
||||
question_mark = { level = "deny" }
|
||||
redundant_closure = { level = "deny" }
|
||||
# Individual rules that have violations in the codebase:
|
||||
type_complexity = "allow"
|
||||
# We often return trait objects from `new` functions.
|
||||
new_ret_no_self = { level = "allow" }
|
||||
# We have a few `next` functions that differ in lifetimes
|
||||
# compared to Iterator::next. Yet, clippy complains about those.
|
||||
should_implement_trait = { level = "allow" }
|
||||
module_inception = { level = "deny" }
|
||||
# Individual rules that have violations in the codebase:
|
||||
type_complexity = "allow"
|
||||
|
||||
[workspace.metadata.cargo-machete]
|
||||
ignored = ["bindgen", "cbindgen", "prost_build", "serde"]
|
||||
|
@ -329,7 +329,7 @@ impl AssistantPanel {
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
let model_selector_menu_handle = PopoverMenuHandle::default();
|
||||
let model_summary_editor = cx.new_view(|cx| Editor::single_line(cx));
|
||||
let model_summary_editor = cx.new_view(Editor::single_line);
|
||||
let context_editor_toolbar = cx.new_view(|_| {
|
||||
ContextEditorToolbarItem::new(
|
||||
workspace,
|
||||
@ -1097,7 +1097,7 @@ impl AssistantPanel {
|
||||
pane.activate_item(configuration_item_ix, true, true, cx);
|
||||
});
|
||||
} else {
|
||||
let configuration = cx.new_view(|cx| ConfigurationView::new(cx));
|
||||
let configuration = cx.new_view(ConfigurationView::new);
|
||||
self.configuration_subscription = Some(cx.subscribe(
|
||||
&configuration,
|
||||
|this, _, event: &ConfigurationViewEvent, cx| match event {
|
||||
@ -4222,8 +4222,7 @@ impl Item for ContextEditor {
|
||||
}
|
||||
|
||||
fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| Item::deactivated(editor, cx))
|
||||
self.editor.update(cx, Item::deactivated)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -700,7 +700,7 @@ impl Context {
|
||||
telemetry: Option<Arc<Telemetry>>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Self {
|
||||
let id = saved_context.id.clone().unwrap_or_else(|| ContextId::new());
|
||||
let id = saved_context.id.clone().unwrap_or_else(ContextId::new);
|
||||
let mut this = Self::new(
|
||||
id,
|
||||
ReplicaId::default(),
|
||||
|
@ -390,7 +390,7 @@ impl ContextStore {
|
||||
context_proto
|
||||
.operations
|
||||
.into_iter()
|
||||
.map(|op| ContextOperation::from_proto(op))
|
||||
.map(ContextOperation::from_proto)
|
||||
.collect::<Result<Vec<_>>>()
|
||||
})
|
||||
.await?;
|
||||
@ -527,7 +527,7 @@ impl ContextStore {
|
||||
context_proto
|
||||
.operations
|
||||
.into_iter()
|
||||
.map(|op| ContextOperation::from_proto(op))
|
||||
.map(ContextOperation::from_proto)
|
||||
.collect::<Result<Vec<_>>>()
|
||||
})
|
||||
.await?;
|
||||
|
@ -3073,7 +3073,7 @@ mod tests {
|
||||
codegen.handle_stream(
|
||||
String::new(),
|
||||
range,
|
||||
future::ready(Ok(chunks_rx.map(|chunk| Ok(chunk)).boxed())),
|
||||
future::ready(Ok(chunks_rx.map(Ok).boxed())),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
@ -3145,7 +3145,7 @@ mod tests {
|
||||
codegen.handle_stream(
|
||||
String::new(),
|
||||
range.clone(),
|
||||
future::ready(Ok(chunks_rx.map(|chunk| Ok(chunk)).boxed())),
|
||||
future::ready(Ok(chunks_rx.map(Ok).boxed())),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
@ -3220,7 +3220,7 @@ mod tests {
|
||||
codegen.handle_stream(
|
||||
String::new(),
|
||||
range.clone(),
|
||||
future::ready(Ok(chunks_rx.map(|chunk| Ok(chunk)).boxed())),
|
||||
future::ready(Ok(chunks_rx.map(Ok).boxed())),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
@ -3294,7 +3294,7 @@ mod tests {
|
||||
codegen.handle_stream(
|
||||
String::new(),
|
||||
range.clone(),
|
||||
future::ready(Ok(chunks_rx.map(|chunk| Ok(chunk)).boxed())),
|
||||
future::ready(Ok(chunks_rx.map(Ok).boxed())),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
@ -253,7 +253,7 @@ fn tab_items_for_queries(
|
||||
.fold(HashMap::default(), |mut candidates, (id, path_string)| {
|
||||
candidates
|
||||
.entry(path_string)
|
||||
.or_insert_with(|| Vec::new())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(id);
|
||||
candidates
|
||||
});
|
||||
|
@ -529,14 +529,13 @@ mod test {
|
||||
let (a, b) = cx.update(|cx| {
|
||||
(
|
||||
one_at_a_time.spawn(cx, |_| async {
|
||||
assert!(false);
|
||||
Ok(2)
|
||||
panic!("");
|
||||
}),
|
||||
one_at_a_time.spawn(cx, |_| async { Ok(3) }),
|
||||
)
|
||||
});
|
||||
|
||||
assert_eq!(a.await.unwrap(), None);
|
||||
assert_eq!(a.await.unwrap(), None::<u32>);
|
||||
assert_eq!(b.await.unwrap(), Some(3));
|
||||
|
||||
let promise = cx.update(|cx| one_at_a_time.spawn(cx, |_| async { Ok(4) }));
|
||||
|
@ -30,7 +30,7 @@ struct CheckIsContributorParams {
|
||||
}
|
||||
|
||||
impl CheckIsContributorParams {
|
||||
fn as_contributor_selector(self) -> Result<ContributorSelector> {
|
||||
fn into_contributor_selector(self) -> Result<ContributorSelector> {
|
||||
if let Some(github_user_id) = self.github_user_id {
|
||||
return Ok(ContributorSelector::GitHubUserId { github_user_id });
|
||||
}
|
||||
@ -54,7 +54,7 @@ async fn check_is_contributor(
|
||||
Extension(app): Extension<Arc<AppState>>,
|
||||
Query(params): Query<CheckIsContributorParams>,
|
||||
) -> Result<Json<CheckIsContributorResponse>> {
|
||||
let params = params.as_contributor_selector()?;
|
||||
let params = params.into_contributor_selector()?;
|
||||
|
||||
if RenovateBot::is_renovate_bot(¶ms) {
|
||||
return Ok(Json(CheckIsContributorResponse {
|
||||
|
@ -1326,9 +1326,7 @@ impl ActionEventRow {
|
||||
}
|
||||
|
||||
pub fn calculate_json_checksum(app: Arc<AppState>, json: &impl AsRef<[u8]>) -> Option<Vec<u8>> {
|
||||
let Some(checksum_seed) = app.config.zed_client_checksum_seed.as_ref() else {
|
||||
return None;
|
||||
};
|
||||
let checksum_seed = app.config.zed_client_checksum_seed.as_ref()?;
|
||||
|
||||
let mut summer = Sha256::new();
|
||||
summer.update(checksum_seed);
|
||||
|
@ -52,7 +52,7 @@ async fn get_extensions(
|
||||
let extension_id = filter.to_lowercase();
|
||||
let mut exact_match = None;
|
||||
extensions.retain(|extension| {
|
||||
if extension.id.as_ref() == &extension_id {
|
||||
if extension.id.as_ref() == extension_id {
|
||||
exact_match = Some(extension.clone());
|
||||
false
|
||||
} else {
|
||||
|
@ -872,7 +872,7 @@ fn operation_from_storage(
|
||||
})
|
||||
}
|
||||
|
||||
fn version_to_storage(version: &Vec<proto::VectorClockEntry>) -> Vec<storage::VectorClockEntry> {
|
||||
fn version_to_storage(version: &[proto::VectorClockEntry]) -> Vec<storage::VectorClockEntry> {
|
||||
version
|
||||
.iter()
|
||||
.map(|entry| storage::VectorClockEntry {
|
||||
@ -882,7 +882,7 @@ fn version_to_storage(version: &Vec<proto::VectorClockEntry>) -> Vec<storage::Ve
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn version_from_storage(version: &Vec<storage::VectorClockEntry>) -> Vec<proto::VectorClockEntry> {
|
||||
fn version_from_storage(version: &[storage::VectorClockEntry]) -> Vec<proto::VectorClockEntry> {
|
||||
version
|
||||
.iter()
|
||||
.map(|entry| proto::VectorClockEntry {
|
||||
|
@ -146,11 +146,11 @@ impl Database {
|
||||
pub async fn update_dev_server_project(
|
||||
&self,
|
||||
id: DevServerProjectId,
|
||||
paths: &Vec<String>,
|
||||
paths: &[String],
|
||||
user_id: UserId,
|
||||
) -> crate::Result<(dev_server_project::Model, proto::DevServerProjectsUpdate)> {
|
||||
self.transaction(move |tx| async move {
|
||||
let paths = paths.clone();
|
||||
let paths = paths.to_owned();
|
||||
let Some((project, Some(dev_server))) = dev_server_project::Entity::find_by_id(id)
|
||||
.find_also_related(dev_server::Entity)
|
||||
.one(&*tx)
|
||||
|
@ -5,7 +5,7 @@ use super::*;
|
||||
impl Database {
|
||||
pub async fn get_hosted_projects(
|
||||
&self,
|
||||
channel_ids: &Vec<ChannelId>,
|
||||
channel_ids: &[ChannelId],
|
||||
roles: &HashMap<ChannelId, ChannelRole>,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<Vec<proto::HostedProject>> {
|
||||
|
@ -88,7 +88,7 @@ async fn main() -> Result<()> {
|
||||
.route("/healthz", get(handle_liveness_probe))
|
||||
.layer(Extension(mode));
|
||||
|
||||
let listener = TcpListener::bind(&format!("0.0.0.0:{}", config.http_port))
|
||||
let listener = TcpListener::bind(format!("0.0.0.0:{}", config.http_port))
|
||||
.expect("failed to bind TCP listener");
|
||||
|
||||
let mut on_shutdown = None;
|
||||
|
@ -346,7 +346,7 @@ impl MessageEditor {
|
||||
) -> Option<(Anchor, String, Vec<StringMatchCandidate>)> {
|
||||
let end_offset = end_anchor.to_offset(buffer.read(cx));
|
||||
|
||||
let Some(query) = buffer.update(cx, |buffer, _| {
|
||||
let query = buffer.update(cx, |buffer, _| {
|
||||
let mut query = String::new();
|
||||
for ch in buffer.reversed_chars_at(end_offset).take(100) {
|
||||
if ch == '@' {
|
||||
@ -358,9 +358,7 @@ impl MessageEditor {
|
||||
query.push(ch);
|
||||
}
|
||||
None
|
||||
}) else {
|
||||
return None;
|
||||
};
|
||||
})?;
|
||||
|
||||
let start_offset = end_offset - query.len();
|
||||
let start_anchor = buffer.read(cx).anchor_before(start_offset);
|
||||
@ -414,7 +412,7 @@ impl MessageEditor {
|
||||
|
||||
let end_offset = end_anchor.to_offset(buffer.read(cx));
|
||||
|
||||
let Some(query) = buffer.update(cx, |buffer, _| {
|
||||
let query = buffer.update(cx, |buffer, _| {
|
||||
let mut query = String::new();
|
||||
for ch in buffer.reversed_chars_at(end_offset).take(100) {
|
||||
if ch == ':' {
|
||||
@ -450,9 +448,7 @@ impl MessageEditor {
|
||||
query.push(ch);
|
||||
}
|
||||
None
|
||||
}) else {
|
||||
return None;
|
||||
};
|
||||
})?;
|
||||
|
||||
let start_offset = end_offset - query.len() - 1;
|
||||
let start_anchor = buffer.read(cx).anchor_before(start_offset);
|
||||
|
@ -448,7 +448,7 @@ fn history_file_exists(abs_path: &PathBuf) -> bool {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn history_file_exists(abs_path: &PathBuf) -> bool {
|
||||
fn history_file_exists(abs_path: &Path) -> bool {
|
||||
!abs_path.ends_with("nonexistent.rs")
|
||||
}
|
||||
|
||||
|
@ -2012,7 +2012,7 @@ fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
|
||||
}
|
||||
|
||||
fn test_path_position(test_str: &str) -> FileSearchQuery {
|
||||
let path_position = PathWithPosition::parse_str(&test_str);
|
||||
let path_position = PathWithPosition::parse_str(test_str);
|
||||
|
||||
FileSearchQuery {
|
||||
raw_query: test_str.to_owned(),
|
||||
|
@ -181,7 +181,7 @@ impl PickerDelegate for OpenPathDelegate {
|
||||
}
|
||||
|
||||
let matches = fuzzy::match_strings(
|
||||
&match_candidates.as_slice(),
|
||||
match_candidates.as_slice(),
|
||||
&suffix,
|
||||
false,
|
||||
100,
|
||||
|
@ -4301,7 +4301,7 @@ pub fn trailing_whitespace_ranges(rope: &Rope) -> Vec<Range<usize>> {
|
||||
let mut prev_line_trailing_whitespace_range = 0..0;
|
||||
for (i, line) in chunk.split('\n').enumerate() {
|
||||
let line_end_offset = offset + line.len();
|
||||
let trimmed_line_len = line.trim_end_matches(|c| matches!(c, ' ' | '\t')).len();
|
||||
let trimmed_line_len = line.trim_end_matches([' ', '\t']).len();
|
||||
let mut trailing_whitespace_range = (offset + trimmed_line_len)..line_end_offset;
|
||||
|
||||
if i == 0 && trimmed_line_len == 0 {
|
||||
|
@ -145,7 +145,7 @@ impl super::LspAdapter for GoLspAdapter {
|
||||
let this = *self;
|
||||
|
||||
if let Some(version) = *version {
|
||||
let binary_path = container_dir.join(&format!("gopls_{version}"));
|
||||
let binary_path = container_dir.join(format!("gopls_{version}"));
|
||||
if let Ok(metadata) = fs::metadata(&binary_path).await {
|
||||
if metadata.is_file() {
|
||||
remove_matching(&container_dir, |entry| {
|
||||
@ -198,7 +198,7 @@ impl super::LspAdapter for GoLspAdapter {
|
||||
.find(version_stdout)
|
||||
.with_context(|| format!("failed to parse golps version output '{version_stdout}'"))?
|
||||
.as_str();
|
||||
let binary_path = container_dir.join(&format!("gopls_{version}"));
|
||||
let binary_path = container_dir.join(format!("gopls_{version}"));
|
||||
fs::rename(&installed_binary_path, &binary_path).await?;
|
||||
|
||||
Ok(LanguageServerBinary {
|
||||
|
@ -5601,14 +5601,14 @@ impl LspStore {
|
||||
{
|
||||
if let Some(watched_paths) = self
|
||||
.language_server_watched_paths
|
||||
.get(&server_id)
|
||||
.get(server_id)
|
||||
.and_then(|paths| paths.read(cx).worktree_paths.get(&worktree_id))
|
||||
{
|
||||
let params = lsp::DidChangeWatchedFilesParams {
|
||||
changes: changes
|
||||
.iter()
|
||||
.filter_map(|(path, _, change)| {
|
||||
if !watched_paths.is_match(&path) {
|
||||
if !watched_paths.is_match(path) {
|
||||
return None;
|
||||
}
|
||||
let typ = match change {
|
||||
|
@ -388,9 +388,7 @@ impl PickerDelegate for RecentProjectsDelegate {
|
||||
selected: bool,
|
||||
cx: &mut ViewContext<Picker<Self>>,
|
||||
) -> Option<Self::ListItem> {
|
||||
let Some(hit) = self.matches.get(ix) else {
|
||||
return None;
|
||||
};
|
||||
let hit = self.matches.get(ix)?;
|
||||
|
||||
let (_, location) = self.workspaces.get(hit.candidate_id)?;
|
||||
|
||||
|
@ -156,7 +156,7 @@ impl SshSession {
|
||||
run_cmd(socket.ssh_command(&remote_binary_path).arg("version")).await?;
|
||||
|
||||
let mut remote_server_child = socket
|
||||
.ssh_command(&format!(
|
||||
.ssh_command(format!(
|
||||
"RUST_LOG={} {:?} run",
|
||||
std::env::var("RUST_LOG").unwrap_or_default(),
|
||||
remote_binary_path,
|
||||
@ -661,7 +661,7 @@ impl SshClientState {
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.arg(src_path)
|
||||
.arg(&format!(
|
||||
.arg(format!(
|
||||
"{}:{}",
|
||||
self.socket.connection_options.scp_url(),
|
||||
dest_path.display()
|
||||
|
@ -51,9 +51,7 @@ impl PickerDelegate for Delegate {
|
||||
selected: bool,
|
||||
_cx: &mut gpui::ViewContext<Picker<Self>>,
|
||||
) -> Option<Self::ListItem> {
|
||||
let Some(candidate_ix) = self.matches.get(ix) else {
|
||||
return None;
|
||||
};
|
||||
let candidate_ix = self.matches.get(ix)?;
|
||||
// TASK: Make StringMatchCandidate::string a SharedString
|
||||
let candidate = SharedString::from(self.candidates[*candidate_ix].string.clone());
|
||||
|
||||
|
@ -1889,16 +1889,15 @@ mod tests {
|
||||
cells
|
||||
}
|
||||
|
||||
fn convert_cells_to_content(size: TerminalSize, cells: &Vec<Vec<char>>) -> TerminalContent {
|
||||
fn convert_cells_to_content(size: TerminalSize, cells: &[Vec<char>]) -> TerminalContent {
|
||||
let mut ic = Vec::new();
|
||||
|
||||
for row in 0..cells.len() {
|
||||
for col in 0..cells[row].len() {
|
||||
let cell_char = cells[row][col];
|
||||
for (index, row) in cells.iter().enumerate() {
|
||||
for (cell_index, cell_char) in row.iter().enumerate() {
|
||||
ic.push(IndexedCell {
|
||||
point: AlacPoint::new(Line(row as i32), Column(col)),
|
||||
point: AlacPoint::new(Line(index as i32), Column(cell_index)),
|
||||
cell: Cell {
|
||||
c: cell_char,
|
||||
c: *cell_char,
|
||||
..Default::default()
|
||||
},
|
||||
});
|
||||
|
@ -190,7 +190,7 @@ impl ZedSyntaxToken {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_vscode(&self) -> Vec<&'static str> {
|
||||
fn to_vscode(self) -> Vec<&'static str> {
|
||||
match self {
|
||||
ZedSyntaxToken::Attribute => vec!["entity.other.attribute-name"],
|
||||
ZedSyntaxToken::Boolean => vec!["constant.language"],
|
||||
|
@ -1,5 +1,5 @@
|
||||
mod button;
|
||||
pub(self) mod button_icon;
|
||||
mod button_icon;
|
||||
mod button_like;
|
||||
mod icon_button;
|
||||
mod toggle_button;
|
||||
|
@ -13,6 +13,12 @@ pub struct List {
|
||||
children: SmallVec<[AnyElement; 2]>,
|
||||
}
|
||||
|
||||
impl Default for List {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl List {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
|
@ -202,9 +202,7 @@ impl VimCommand {
|
||||
query = &query[..query.len() - 1];
|
||||
}
|
||||
|
||||
let Some(suffix) = query.strip_prefix(self.prefix) else {
|
||||
return None;
|
||||
};
|
||||
let suffix = query.strip_prefix(self.prefix)?;
|
||||
if !self.suffix.starts_with(suffix) {
|
||||
return None;
|
||||
}
|
||||
|
@ -135,9 +135,7 @@ impl Vim {
|
||||
self.store_visual_marks(cx);
|
||||
let Some(pane) = self.pane(cx) else { return };
|
||||
let result = pane.update(cx, |pane, cx| {
|
||||
let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() else {
|
||||
return None;
|
||||
};
|
||||
let search_bar = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>()?;
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
let mut count = self.search.count;
|
||||
let direction = self.search.direction;
|
||||
@ -420,12 +418,9 @@ impl Replacement {
|
||||
// but we do flip \( and \) to ( and ) (and vice-versa) in the pattern,
|
||||
// and convert \0..\9 to $0..$9 in the replacement so that common idioms work.
|
||||
pub(crate) fn parse(mut chars: Peekable<Chars>) -> Option<Replacement> {
|
||||
let Some(delimiter) = chars
|
||||
let delimiter = chars
|
||||
.next()
|
||||
.filter(|c| !c.is_alphanumeric() && *c != '"' && *c != '|' && *c != '\'')
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
.filter(|c| !c.is_alphanumeric() && *c != '"' && *c != '|' && *c != '\'')?;
|
||||
|
||||
let mut search = String::new();
|
||||
let mut replacement = String::new();
|
||||
|
@ -875,9 +875,7 @@ fn surrounding_markers(
|
||||
}
|
||||
}
|
||||
|
||||
let Some(mut opening) = opening else {
|
||||
return None;
|
||||
};
|
||||
let mut opening = opening?;
|
||||
|
||||
let mut matched_opens = 0;
|
||||
let mut closing = None;
|
||||
@ -905,9 +903,7 @@ fn surrounding_markers(
|
||||
before_ch = ch;
|
||||
}
|
||||
|
||||
let Some(mut closing) = closing else {
|
||||
return None;
|
||||
};
|
||||
let mut closing = closing?;
|
||||
|
||||
if around && !search_across_lines {
|
||||
let mut found = false;
|
||||
|
@ -1075,10 +1075,9 @@ fn parse_url_arg(arg: &str, cx: &AppContext) -> Result<String> {
|
||||
if arg.starts_with("file://")
|
||||
|| arg.starts_with("zed-cli://")
|
||||
|| arg.starts_with("ssh://")
|
||||
|| parse_zed_link(arg, cx).is_some()
|
||||
{
|
||||
Ok(arg.into())
|
||||
} else if parse_zed_link(arg, cx).is_some() {
|
||||
Ok(arg.into())
|
||||
} else {
|
||||
Err(anyhow!("error parsing path argument: {}", error))
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ fn connect_to_cli(
|
||||
}
|
||||
|
||||
pub async fn open_paths_with_positions(
|
||||
path_positions: &Vec<PathWithPosition>,
|
||||
path_positions: &[PathWithPosition],
|
||||
app_state: Arc<AppState>,
|
||||
open_options: workspace::OpenOptions,
|
||||
cx: &mut AsyncAppContext,
|
||||
|
Loading…
Reference in New Issue
Block a user